Commit graph

186 commits

Author SHA1 Message Date
Robert Müller ebb2e4253d Port line input and IME support from 0.7
Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397.

General
------------------------------

Fix issues with the text input. Closes #4346. Closes #4524.

Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference.

Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved.

UI text input
------------------------------

Fix inconsistent mouse-based left and right scrolling (closes #4347).

Support smooth left and right scrolling.

Chat
------------------------------

Support keyboard-based text selection of the chat input.

Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor.

Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling.

Console
------------------------------

Also support mouse-based text selection of the command input.

Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console.

Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice).

When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log.

Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected.

Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end.

Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead.

IME support
------------------------------

Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems.

Improve composition rendering by underlining the composition text instead of putting it in square brackets.

Track active input globally to properly activate and deactivate IME through the SDL functions.

Closes #1030. Closes #1008.

Password rendering
------------------------------

Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint.

Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could:

1. Use a latin password and switch off the IME for the password input with the IME hotkey.
2. Blank your screen with an external program while you are streaming and entering passwords.
3. Use binds to authenticate in rcon or to set the server browser password.

Refactoring
------------------------------

Move all text input logic and general rendering to `CLineInput`.

A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead).

Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer.

Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input.

Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text.

Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input.

Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer.

Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`.

Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering.

Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer.

Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use.

IME usage guide (Windows)
------------------------------

1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean).
2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally.
2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing).
3. Switch from Latin/English input mode to the respective asian input mode.
   - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings.
   - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings.
   - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet.
   - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately.
4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list.

SDL version-specific issues
------------------------------

- 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor.
- 2.0.18, 2.0.20: IME candidates work.
- 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode.
- 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-04-23 15:00:29 +02:00
Robert Müller f77af29094 Add text cursor setting to always render caret (disable blinking)
Add flag to temporarily cause the caret to not blink, so the caret can be rendered without blinking after it has been moved, which greatly improves usability.
2023-04-23 15:00:26 +02:00
Robert Müller 08b0a03ca4 Render selection in front of text instead of behind it
Makes the text selection easier to see, especially when the text selection height is lower than normal.

Change text selection color to light grey instead of blue.
2023-04-23 15:00:25 +02:00
Robert Müller ca90d83c10 Allow adjusting height factor of text selection rectangle
Add `CTextCursor::m_SelectionHeightFactor` setting to adjust the height of the text selection rectangle. For example a value of `0.5f` means that the selection rectangle has half its normal height while still being aligned at the same bottom position.
2023-04-23 15:00:25 +02:00
Robert Müller 928d278d0c Rename DefaultSelectionColor for consistency
The other methods also start with `Text`.
2023-04-15 16:58:33 +02:00
Robert Müller ea058d9d2e Replace CharacterCounter with existing pCursor->m_GlyphCount
The separate `CharacterCounter` variable is not necessary, as the same value is already tracked by `pCursor->m_GlyphCount`.
2023-04-15 16:58:05 +02:00
Robert Müller a160364b77 Add default parameters to Text and TextEx 2023-04-15 16:49:53 +02:00
Robert Müller f0c295b2d3 Add length check in AppendTextContainer
Allow `Length` parameter to be longer than maximum string length.
2023-04-15 16:49:53 +02:00
Robert Müller fe40048ca8 Remove unnecessary SetRenderFlags calls
Setting the render flags here is unnecessary, as the render flags are already set identically inside `TextEx`.
2023-04-15 16:49:27 +02:00
Robert Müller a6f9fdd6d5 Add function to get caret position to ITextRender
Add `CaretPosition` function to get position of text caret. Replace some existing usages of `TextWidth`, which would no longer work correctly for multi-line text.

Having this function is also useful when porting the upstream UI lineinput.
2023-04-10 17:22:10 +02:00
Robert Müller 9ad2f9f4df Add functions to get text bounding box to ITextRender
Add separate `STextBoundingBox` to describe text bounding box (same as on upstream). Add `GetBoundingBoxTextContainer` to get bounding box for a text container. Add `TextBoundingBox` function to get bounding box with old text render interface.

Using this function to get the bounding box width and height is cleaner than using `TextWidth`. This function additionally can get the bounding box X and Y position for convenience.

Some usages of `TextWidth` are replaced with `TextBoundingBox` to improve readability.

It will be useful to have these functions when porting the upstream UI lineinput.
2023-04-10 17:22:10 +02:00
Robert Müller bf1e757581 Fix incorrect text width calculation when cursor not starting at X=0
Previously when calculating `m_LongestLineWidth` for a `CTextCursor` the position `m_StartX` of the cursor was always zero, because `m_LongestLineWidth` was only used to calculate the text width with a non-rendered cursor aligned at (0, 0).

To ensure that the calculation is correct also when the text cursor is not positioned at X=0, the width calculation must be offset by the start position.
2023-04-10 16:06:17 +02:00
Robert Müller 9bb9c7ce6b Replace usages of TextLineCount with TextWidth
Calculate text height for popups with `TextWidth` instead of using `TextLineCount`, which can be incorrect if the aligned font size differs from the normal one.
2023-04-09 20:10:44 +02:00
Robert Müller 9693d4beac Fix vertical centering of multi-line UI labels
Also calculate text height in `TextWidth`.

Use calculated text height to verically center UI labels.

The text cursor flags (in particular, the `TEXTFLAG_STOP_AT_END` flag) must also be passed to `TextWidth`. Otherwise, for example, when `TEXTFLAG_STOP_AT_END` is missing, the wrong text height is calculated, as text is rendered over multiple lines instead of stopping at the end of the first line.

Closes #5396.
2023-04-09 20:10:09 +02:00
Robert Müller 0ca6d06fba Fix incorrect text width calculation of multi-line text
For text spanning multiple lines `TextWidth` only returned the length of the last line instead of the length of the longest line.
2023-04-09 20:10:09 +02:00
Robert Müller ad69d62015 Fix long words being printed over maximum line width
When the text render encounters long words which must be broken up, ensure that the words do not exceed the maximum line width.

Closes #6354.
2023-04-09 20:09:52 +02:00
Robert Müller a0f1b4118d Use round_to_int in text render
For positive numbers, which the text positions always are, the result of `(int)(x + 0.5f)` is identical to `round_to_int(x)`.
2023-03-09 23:04:18 +01:00
Robert Müller 3cd294372a Fix text rendering over maximum line width with newline
When a word is rendered over the maximum line width it should be moved to the next line.

However, this was not working correctly if the word ends with a newline instead of a space, because then the text x-advance including this word did not exceed the maximum width, as the newline caused the x-advance to be reset before it can be used.

This is fixed by replacing the unused flag `TEXTFLAG_ALLOW_NEWLINE` with the flag `TEXTFLAG_DISALLOW_NEWLINE`, which causes newline characters to be replaced with space characters. This flag is then used when calculating whether the next word fits in the current line.

Closes #4541.
2023-02-21 23:38:41 +01:00
Robert Müller 8286105804 Use RecreateTextContainer, reorder parameters
The `RecreateTextContainer` function calls `DeleteTextContainer` and then `CreateTextContainer`.

The arguments of `RecreateTextContainer` and `RecreateTextContainerSoft` are reordered so all functions take the text container as their first argument.
2023-02-20 23:39:43 +01:00
Robert Müller f386eff45c Remove unused argument of Text/TextWidth/TextLineCount
The `void *pFontSetV` argument is unused and all invocations except one were already passing `0`, `0x0` or `nullptr` for this argument.
2023-02-20 20:06:17 +01:00
Robert Müller 4284f78bb7 Various refactoring and cleanup of text render
- Use `nullptr` instead of `NULL` and `0`.
- Consistently use `unsigned` for render flags instead of mixing `int` and `unsigned`.
- Use `constexpr` instead of `#define` for constants.
- Use prefix `S` for struct instead of `C`.
- Use `\0` instead of `0` for characters.
- Mark various methods as `const` when possible.
- Mark variables and pointer parameters as `const` when possible.
- Remove `const` from pointer parameters where constness was later removed by casting to `void *` anyway.
- Use `size_t` directly for loop variables and parameters which are being cast to `size_t` later anyway.
- Move variable declarations closer to usages.
- Fix variable names.
- Add/remove empty lines to improve readability.
- Use loops to reduce duplicate code.
- Use `bool` instead of `int`.
- Replace nested `if`s with single `if` using `&&` to reduce indentation and improve readability.
- Remove unnecessary temporary variables.
- Reorder includes.
2023-02-20 20:06:17 +01:00
Robert Müller ec7f5560a3 Fix possible integer overflows using mem_* functions 2023-02-19 13:45:48 +01:00
Robert Müller 3280f1824f Reset graphics container indices after deletion
Reduce duplicate code and improve correctness by passing indices of quad, buffer and text containers by reference and always setting them to `-1` after they are deleted.

Also check if index is `-1` before trying to delete it to reduce duplicate code when calling the methods.
2023-02-15 21:05:15 +01:00
Robert Müller 554fc19be0 Remove unused member SFontSizeChar::m_TouchTime 2022-11-29 23:28:37 +01:00
Rafael Fontenelle cd14660307 Fix misspellings 2022-10-25 13:51:56 -03:00
def c94de9b764 Further clang-tidy 14 issues (fixes #5612) 2022-07-27 09:07:47 +02:00
Robert Müller ec4175277e Fix readability-container-data-pointer 2022-07-10 21:42:57 +02:00
Alexander Akulich 6d9284adc1 Port some code to str_copy() template 2022-07-09 19:40:58 +03:00
bors[bot] e2f7f53bc8
Merge #5591
5591: (A bit) safer interface for text containers r=def- a=Jupeyy

For #5143
Maybe it helps identifying the problem earlier, maybe not^^

## Checklist

- [x] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Jupeyy <jupjopjap@gmail.com>
2022-07-09 09:47:48 +00:00
Jupeyy c6589f3a5e (A bit) safer interface for text containers 2022-07-08 19:19:37 +02:00
Chairn a69dc599a9 Huge variable naming format
Fix pointer and pointer array variable naming

Huge renaming to match our rules

Used regex: (?!(return|delete)\b)\b\w+ (m_|ms_|g_|gs_|s_)[^a]\w+\[
            (?!(return|delete)\b)\b\w+ (?!(m_|ms_|g_|gs_|s_))[^a]\w+\[

Further format static variables

Format almost all pointer names accordingly

Used regex: (?!(return)\b)\b\w+
\*(?!(m_p|p|s_p|m_ap|s_ap|g_p|g_ap|ap|gs_ap|ms_ap|gs_p|ms_p))\w+\b[^:\(p]

clang-format

Fix CI fail

Fix misnamed non pointer as pointer and non array as array

Used regex: (?!(return|delete)\b)\b\w+ (m_|ms_|g_|gs_|s_)p\w+\b
            (?!return\b)\b\w+ (ms_|m_|g_|gs_|s_)a\w+\b[^\[]

clang-format

Revert to SCREAMING_SNAKE_CASE and reinstate dead code
2022-07-08 18:01:29 +02:00
Chairn 32318a7c90 Reworked color system
Removed duplicate structs. Replaced 4 floats array with appropriate
struct where applicable
2022-07-06 11:39:51 +02:00
Robert Müller 16d9a69dd5 Print font name instead of address in log message, pFont -> font 2022-06-28 17:48:41 +02:00
Chairn a9ee57aeb7 Fix unsafe defines 2022-06-27 18:51:02 +02:00
Robert Müller ceca44ea23 Use io_read_all to load icon font 2022-06-16 10:19:37 +02:00
Chairn c9345e7d32 More vector naming format 2022-06-15 19:37:37 +02:00
heinrich5991 b3a3604c36 Remove namespace tw
It didn't have a clear role, it just acted as a distinguisher between
two functions with the same name.

Rename `tw::time_get` to `time_get_nanoseconds` and delete the old
`time_get_nanoseconds`. Move `CCmdlineFix` and the typed
`net_socket_read_wait` function to the global namespace.
2022-06-13 18:07:29 +02:00
Chairn 01edaec628 Format vector variables names (fixes #5209) 2022-06-11 21:38:49 +02:00
c0d3d3v 0914c1260b
add ellipsis again 2022-05-31 12:20:45 +02:00
Robert Müller 4b36584ca1 Organize engine-client includes 2022-05-29 21:24:43 +02:00
def 0c8bf5c3aa Revert "Ellipsis at end in scoreboard and hud"
This reverts commit f278399bd1.
2022-05-22 23:04:32 +02:00
def 590eb2c5d1 Revert "Render full text when it still fits"
This reverts commit c4bcf3d628.
2022-05-22 23:01:00 +02:00
def c4bcf3d628 Render full text when it still fits 2022-05-21 12:12:00 +02:00
def f278399bd1 Ellipsis at end in scoreboard and hud 2022-05-18 23:46:11 +02:00
bors[bot] 609987730c
Merge #5075
5075: Switch to nanoseconds r=def- a=Jupeyy

Modern hardware is too fast, updates sometimes take less than a few microseconds.
It's easier in the long run if we use a bigger range to avoid calculation problems.

possibly f i x e s #5051 (needs testing from bencie for the main bug, but fixes what `@sjrc6` found)

Also took the moment to use more chrono so we can at some point switch to a typesafe time.

Hopefully I didnt miss any value ^^

## Checklist

- [x] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test if it works standalone, system.c especially
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Jupeyy <jupjopjap@gmail.com>
Co-authored-by: Dennis Felsing <dennis@felsin9.de>
2022-05-18 16:59:36 +00:00
Jupeyy a7bc8781a9 Put assert for text containers after printing all non empty text containers 2022-05-18 18:25:48 +02:00
Jupeyy 3c597aff95 Switch to nanoseconds 2022-05-18 18:05:41 +02:00
Dennis Felsing 8d5693d483 Enable clang-tidy's modernize-use-override (fixes #5139)
except for destructors
2022-05-17 20:33:29 +02:00
Jupeyy e54da1b396 Cleanup backend a bit for vulkan 2022-03-20 18:03:25 +01:00
bors[bot] 564a59d603
Merge #4845
4845: Enable -Wshadow=local r=Jupeyy a=def-

> Warn when a local variable shadows another local variable or parameter.

Found one actual bug in graphics_threaded.cpp

Should reduce confusion in the future when reading source code

<!-- What is the motivation for the changes of this pull request -->

## Checklist

- [ ] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test if it works standalone, system.c especially
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: def <dennis@felsin9.de>
2022-03-20 16:45:22 +00:00