Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Widgets/text area #4995

Merged
merged 22 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
8bc9da2
Create TextArea widget, based on `gui/journal` widget
wiktor-obrebski Oct 8, 2024
55ae723
Migrate journal text-area related test to core TestArea test module
wiktor-obrebski Oct 8, 2024
e237387
Add documentation for new TextArea widget
wiktor-obrebski Oct 9, 2024
83a9a19
Add way to set text from the TextArea widget API
wiktor-obrebski Oct 9, 2024
3ce4f1f
Abandon named subviews for TextArea to avoid collisions with user code
wiktor-obrebski Oct 9, 2024
fa68bbe
Improve TextArea docs
wiktor-obrebski Oct 9, 2024
cb549ed
Add tests for TextArea undo feature
wiktor-obrebski Oct 11, 2024
ff41a5e
Add undo/redo textarea widget features tests
wiktor-obrebski Oct 11, 2024
2ed6dcb
Add clear history textarea feature
wiktor-obrebski Oct 11, 2024
58c8d9b
Add history entry (undo/redo) for TextArea API text set (:setText)
wiktor-obrebski Oct 11, 2024
cdda92e
Make TextArea on_cursor_change include old cursor
wiktor-obrebski Nov 17, 2024
a307308
Add docs about how TextArea cursor works
wiktor-obrebski Nov 17, 2024
b9422dc
Add old_text to TextArea widget text change callback
wiktor-obrebski Nov 20, 2024
51ff6b7
Drop now redundant TextArea tests version boundary
wiktor-obrebski Nov 21, 2024
1f75f37
Improve TextArea documentation
wiktor-obrebski Nov 21, 2024
ff76073
Improve TextArea documentation
wiktor-obrebski Nov 21, 2024
6384b21
Improve TextArea focus handling
wiktor-obrebski Nov 21, 2024
6047b40
Polishing TextArea subwidgets
wiktor-obrebski Nov 21, 2024
83f9df3
Remove trailing white space from docs
wiktor-obrebski Nov 22, 2024
4250bb4
Improve TextArea RST documentation structure
wiktor-obrebski Nov 22, 2024
abebac7
Improve TextArea focus
wiktor-obrebski Nov 22, 2024
c005846
Add comment about TextArea rendering
wiktor-obrebski Nov 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 39 additions & 24 deletions docs/dev/Lua API.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5526,7 +5526,7 @@
The cursor in the ``TextArea`` class is index-based, starting from 1,
consistent with Lua's text indexing conventions.

Each character, including new lines (``string.char(10)``),
Each character, including newlines (``string.char(10)``),
occupies a single index in the text content.

Cursor movement and position are fully aware of line breaks,
Expand All @@ -5545,11 +5545,11 @@
* ``init_text``: The initial text content for the text area.

* ``init_cursor``: The initial cursor position within the text content.
myk002 marked this conversation as resolved.
Show resolved Hide resolved
If not specified, defaults to end of the text (length of ``init_text``).
If not specified, defaults to end of the text (length of ``init_text`` + 1).

* ``text_pen``: Optional pen used to draw the text.
* ``text_pen``: Optional pen used to draw the text. Default is ``COLOR_LIGHTCYAN``.

* ``select_pen``: Optional pen used for text selection.
* ``select_pen``: Optional pen used for text selection. Default is ``COLOR_CYAN``.

* ``ignore_keys``: List of input keys to ignore.
Functions similarly to the ``ignore_keys`` attribute in the ``EditField`` class.
Expand All @@ -5560,10 +5560,10 @@
* ``on_cursor_change``: Callback function called whenever the cursor position changes.
Expected function signature is ``on_cursor_change(new_cursor, old_cursor)``.

* ``one_line_mode``: Boolean attribute that, when set to ``true``,
disables multi-line text features and restricts the text area to a single line.
If any "\n" (``string.char(10)``) are available in the text,
they will be removed from the text
* ``one_line_mode``: If set to ``true``, disables multi-line text features.
In this mode the :kbd:`Enter` key is not handled by the widget
as if it were included in ``ignore_keys``.

Check failure on line 5565 in docs/dev/Lua API.rst

View workflow job for this annotation

GitHub Actions / lint / lint

Contains trailing whitespace: line 5565
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
as if it were included in ``ignore_keys``.
as if it were included in ``ignore_keys``.

If multiline text (including ``\n`` chars) is pasted into the widget, newlines are removed.

TextArea Functions:

Expand All @@ -5589,44 +5589,60 @@
* ``textarea:scrollToCursor()``

Scrolls the text area view to ensure that the current cursor position is visible.
This is useful for automatically scrolling when the user moves the cursor
beyond the visible region of the text area.
This happens automatically when the user interactively moves the cursor or
pastes text into the widget, but may need to be called when ``setCursor`` is
called programmatically.

* ``textarea:clearHistory()``

Clear undo/redo history of the widget.
Clears undo/redo history of the widget.

Functionality:
Functionality
-------------
Copy link
Member

@myk002 myk002 Nov 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

welcome to the wonderful world of restructured text header underline rules. Currently, this section is interpreted like this:
image
that is, Functionality is a peer of TextArea class and Cursor Behavior is a higher level header than TextArea class.

You need to scan through the existing headers and discover what underline style is used for what level of header. It's different for every file, and is determined by whatever the file uses first for that particular header depth.

The indentation for list continuation lines is also apparently different from what sphinx expects:
image

You can see how this PR's text is currently rendered here: https://dfhack--4995.org.readthedocs.build/en/4995/docs/dev/Lua%20API.html#textarea-class

You can get to that link by clicking on "details" for the ReadTheDocs build action:
image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank for the tip, I did not know that I can preview docs in build results!
I corrected the docs now.


The TextArea widget provides a familiar and intuitive text editing experience with baseline features such as:

- Text Wrapping: Automatically fits text within the display area.
- Mouse and Keyboard Support: Standard keys like :kbd:`Home`, :kbd:`End`, :kbd:`Backspace`, and :kbd:`Delete` are supported,
along with gestures like double-click to select a word or triple-click to select a line.
- Clipboard Operations: copy, cut, and paste,
with intuitive defaults when no text is selected.
- Undo/Redo: :kbd:`Ctrl` + :kbd:`Z` and :kbd:`Ctrl` + :kbd:`Y` for quick changes.
- Additional features include advanced navigation, line management,
and smooth scrolling for handling long text efficiently.

Detailed list:

- Cursor Control: Navigate through text using arrow keys (Left, Right, Up,
and Down) for precise cursor placement.
- Fast Rewind: Use :kbd:`Ctrl` + :kbd:`Left` and :kbd:`Ctrl` + :kbd:`Right` to
- Mouse Control: Use the mouse to position the cursor within the text,
providing an alternative to keyboard navigation.
- Text Selection: Select text with the mouse, with support for replacing or
removing selected text.
- Select Word/Line: Use double click to select current word, or triple click to
select current line.
- Move By Word: Use :kbd:`Ctrl` + :kbd:`Left` and :kbd:`Ctrl` + :kbd:`Right` to
move the cursor one word back or forward.
- Line Navigation: :kbd:`Home` moves the cursor to the beginning of the current
line, and :kbd:`End` moves it to the end.
- Jump to Beginning/End: Quickly move the cursor to the beginning or end of the
text using :kbd:`Ctrl` + :kbd:`Home` and :kbd:`Ctrl` + :kbd:`End`.
- Longest X Position Memory: The cursor remembers the longest x position when
moving up or down, making vertical navigation more intuitive.
- Mouse Control: Use the mouse to position the cursor within the text,
providing an alternative to keyboard navigation.
- New Lines: Easily insert new lines using the :kbd:`Enter` key, supporting
multiline text input.
- Text Wrapping: Text automatically wraps within the editor, ensuring lines fit
within the display without manual adjustments.
- Scrolling behaviour for long text build-in.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Scrolling behaviour for long text build-in.
- Scrolling for long text entries.

- Backspace Support: Use the backspace key to delete characters to the left of
the cursor.
- Delete Character: :kbd:`Delete` deletes the character under the cursor.
- Line Navigation: :kbd:`Home` moves the cursor to the beginning of the current
line, and :kbd:`End` moves it to the end.
- Delete Current Line: :kbd:`Ctrl` + :kbd:`U` deletes the entire current line
where the cursor is located.
- Delete Rest of Line: :kbd:`Ctrl` + :kbd:`K` deletes text from the cursor to
the end of the line.
- Delete Last Word: :kbd:`Ctrl` + :kbd:`W` removes the word immediately before
the cursor.
- Text Selection: Select text with the mouse, with support for replacing or
removing selected text.
- Jump to Beginning/End: Quickly move the cursor to the beginning or end of the
text using :kbd:`Ctrl` + :kbd:`Home` and :kbd:`Ctrl` + :kbd:`End`.
- Select Word/Line: Use double click to select current word, or triple click to
select current line.
- Select All: Select entire text by :kbd:`Ctrl` + :kbd:`A`.
- Undo/Redo: Undo/Redo changes by :kbd:`Ctrl` + :kbd:`Z` / :kbd:`Ctrl` +
:kbd:`Y`.
Expand All @@ -5645,7 +5661,6 @@
the editor.
- replace selected text, if available
- If no text is selected, paste text in the cursor position
- Scrolling behaviour for long text build-in.

Scrollbar class
---------------
Expand Down
13 changes: 6 additions & 7 deletions library/lua/gui/widgets/text_area.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ TextArea.ATTRS{
init_text = '',
wiktor-obrebski marked this conversation as resolved.
Show resolved Hide resolved
init_cursor = DEFAULT_NIL,
text_pen = COLOR_LIGHTCYAN,
ignore_keys = {'STRING_A096'},
ignore_keys = {},
select_pen = COLOR_CYAN,
on_text_change = DEFAULT_NIL,
on_cursor_change = DEFAULT_NIL,
Expand Down Expand Up @@ -52,7 +52,6 @@ function TextArea:init()
self.text_area,
self.scrollbar,
}
self:setFocus(true)
end

function TextArea:getText()
Expand Down Expand Up @@ -101,15 +100,15 @@ end

function TextArea:scrollToCursor(cursor_offset)
if self.scrollbar.visible then
local _, cursor_liny_y = self.text_area.wrapped_text:indexToCoords(
local _, cursor_line_y = self.text_area.wrapped_text:indexToCoords(
cursor_offset
)
self:updateScrollbar(cursor_liny_y)
self:updateScrollbar(cursor_line_y)
end
end

function TextArea:getPreferredFocusState()
return self.parent_view.focus
return self.parent_view and self.parent_view.focus or true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just true?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I read the docs, but I was always confused by this "preferred focus" feature.
Changed to true

end

function TextArea:postUpdateLayout()
Expand Down Expand Up @@ -144,10 +143,10 @@ end
function TextArea:updateScrollbar(scrollbar_current_y)
local lines_count = #self.text_area.wrapped_text.lines

local render_start_line_y = (math.min(
local render_start_line_y = math.min(
#self.text_area.wrapped_text.lines - self.text_area.frame_body.height + 1,
math.max(1, scrollbar_current_y)
))
)

self.scrollbar:update(
render_start_line_y,
Expand Down
8 changes: 2 additions & 6 deletions library/lua/gui/widgets/text_area/text_area_content.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ TextAreaContent = defclass(TextAreaContent, Widget)
TextAreaContent.ATTRS{
text = '',
text_pen = COLOR_LIGHTCYAN,
ignore_keys = {'STRING_A096'},
ignore_keys = {},
pen_selection = COLOR_CYAN,
on_text_change = DEFAULT_NIL,
on_cursor_change = DEFAULT_NIL,
enable_cursor_blink = true,
debug = false,
one_line_mode = false,
history_size = 10,
history_size = 25,
}

function TextAreaContent:init()
Expand Down Expand Up @@ -63,10 +63,6 @@ function TextAreaContent:setRenderStartLineY(render_start_line_y)
self.render_start_line_y = render_start_line_y
end

function TextAreaContent:getPreferredFocusState()
return true
end

function TextAreaContent:postComputeFrame()
self:recomputeLines()
end
Expand Down
2 changes: 1 addition & 1 deletion library/lua/gui/widgets/text_area/wrapped_text.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ WrappedText = defclass(WrappedText)

WrappedText.ATTRS{
text = '',
wrap_width = DEFAULT_NIL,
wrap_width = math.huge,
}

function WrappedText:init()
Expand Down
7 changes: 0 additions & 7 deletions test/library/gui/widgets.TextArea.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ local widgets = require('gui.widgets')

config.target = 'core'

local df_major_version = tonumber(dfhack.getCompiledDFVersion():match('%d+'))

local function simulate_input_keys(...)
local keys = {...}
for _,key in ipairs(keys) do
Expand Down Expand Up @@ -2881,11 +2879,6 @@ function test.scroll_follows_cursor()
screen:dismiss()
end

if df_major_version < 51 then
-- temporary ignore test features that base on newest API of the DF game
return
end

function test.fast_rewind_words_right()
local text_area, screen, window = arrange_textarea({w=55})

Expand Down
Loading