LMMS
Loading...
Searching...
No Matches
juce_AccessibilityTextHelpers.h
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26namespace juce
27{
28
30{
31 /* Wraps a CharPtr into a stdlib-compatible iterator.
32
33 MSVC's std::reverse_iterator requires the wrapped iterator to be default constructible
34 when building in C++20 mode, but I don't really want to add public default constructors to
35 the CharPtr types. Instead, we add a very basic default constructor here which sets the
36 wrapped CharPtr to nullptr.
37 */
38 template <typename CharPtr>
40 {
41 public:
43 using value_type = decltype (*std::declval<CharPtr>());
46 using iterator_category = std::bidirectional_iterator_tag;
47
49 constexpr explicit CharPtrIteratorAdapter (CharPtr arg) : ptr (arg) {}
50
51 constexpr auto operator*() const { return *ptr; }
52
54 {
55 ++ptr;
56 return *this;
57 }
58
60 {
61 --ptr;
62 return *this;
63 }
64
65 constexpr bool operator== (const CharPtrIteratorAdapter& other) const { return ptr == other.ptr; }
66 constexpr bool operator!= (const CharPtrIteratorAdapter& other) const { return ptr != other.ptr; }
67
68 constexpr auto operator+ (difference_type offset) const { return CharPtrIteratorAdapter { ptr + offset }; }
69 constexpr auto operator- (difference_type offset) const { return CharPtrIteratorAdapter { ptr - offset }; }
70
71 private:
72 CharPtr ptr { {} };
73 };
74
75 template <typename CharPtr>
76 static auto makeCharPtrIteratorAdapter (CharPtr ptr)
77 {
79 }
80
81 enum class BoundaryType
82 {
83 character,
85 line,
86 document
87 };
88
89 enum class Direction
90 {
91 forwards,
92 backwards
93 };
94
95 enum class ExtendSelection
96 {
99 };
100
101 /* Indicates whether a function may return the current text position, in the case that the
102 position already falls on a text unit boundary.
103 */
105 {
106 no, //< Always search for the following boundary, even if the current position falls on a boundary
107 yes //< Return the current position if it falls on a boundary
108 };
109
110 /* Indicates whether a word boundary should include any whitespaces that follow the
111 non-whitespace characters.
112 */
114 {
115 no, //< The word ends on the first whitespace character
116 yes //< The word ends after the last whitespace character
117 };
118
119 /* Like std::distance, but always does an O(N) count rather than an O(1) count, and doesn't
120 require the iterators to have any member type aliases.
121 */
122 template <typename Iter>
123 static int countDifference (Iter from, Iter to)
124 {
125 int distance = 0;
126
127 while (from != to)
128 {
129 ++from;
130 ++distance;
131 }
132
133 return distance;
134 }
135
136 /* Returns the number of characters between ptr and the next word end in a specific
137 direction.
138
139 If ptr is inside a word, the result will be the distance to the end of the same
140 word.
141 */
142 template <typename CharPtr>
143 static int findNextWordEndOffset (CharPtr beginIn,
144 CharPtr endIn,
145 CharPtr ptrIn,
146 Direction direction,
147 IncludeThisBoundary includeBoundary,
148 IncludeWhitespaceAfterWords includeWhitespace)
149 {
150 const auto begin = makeCharPtrIteratorAdapter (beginIn);
151 const auto end = makeCharPtrIteratorAdapter (endIn);
152 const auto ptr = makeCharPtrIteratorAdapter (ptrIn);
153
154 const auto move = [&] (auto b, auto e, auto iter)
155 {
156 const auto isSpace = [] (juce_wchar c) { return CharacterFunctions::isWhitespace (c); };
157
158 const auto start = [&]
159 {
160 if (iter == b && includeBoundary == IncludeThisBoundary::yes)
161 return b;
162
163 const auto nudged = iter - (iter != b && includeBoundary == IncludeThisBoundary::yes ? 1 : 0);
164
165 return includeWhitespace == IncludeWhitespaceAfterWords::yes
166 ? std::find_if (nudged, e, isSpace)
167 : std::find_if_not (nudged, e, isSpace);
168 }();
169
170 const auto found = includeWhitespace == IncludeWhitespaceAfterWords::yes
171 ? std::find_if_not (start, e, isSpace)
172 : std::find_if (start, e, isSpace);
173
174 return countDifference (iter, found);
175 };
176
177 return direction == Direction::forwards ? move (begin, end, ptr)
178 : -move (std::make_reverse_iterator (end),
179 std::make_reverse_iterator (begin),
180 std::make_reverse_iterator (ptr));
181 }
182
183 /* Returns the number of characters between ptr and the beginning of the next line in a
184 specific direction.
185 */
186 template <typename CharPtr>
187 static int findNextLineOffset (CharPtr beginIn,
188 CharPtr endIn,
189 CharPtr ptrIn,
190 Direction direction,
191 IncludeThisBoundary includeBoundary)
192 {
193 const auto begin = makeCharPtrIteratorAdapter (beginIn);
194 const auto end = makeCharPtrIteratorAdapter (endIn);
195 const auto ptr = makeCharPtrIteratorAdapter (ptrIn);
196
197 const auto findNewline = [] (auto from, auto to) { return std::find (from, to, juce_wchar { '\n' }); };
198
199 if (direction == Direction::forwards)
200 {
201 if (ptr != begin && includeBoundary == IncludeThisBoundary::yes && *(ptr - 1) == '\n')
202 return 0;
203
204 const auto newline = findNewline (ptr, end);
205 return countDifference (ptr, newline) + (newline == end ? 0 : 1);
206 }
207
208 const auto rbegin = std::make_reverse_iterator (ptr);
209 const auto rend = std::make_reverse_iterator (begin);
210
211 return -countDifference (rbegin, findNewline (rbegin + (rbegin == rend || includeBoundary == IncludeThisBoundary::yes ? 0 : 1), rend));
212 }
213
214 /* Unfortunately, the method of computing end-points of text units depends on context, and on
215 the current platform.
216
217 Some examples of different behaviour:
218 - On Android, updating the cursor/selection always searches for the next text unit boundary;
219 but on Windows, ExpandToEnclosingUnit() should not move the starting point of the
220 selection if it already at a unit boundary. This means that we need both inclusive and
221 exclusive methods for finding the next text boundary.
222 - On Android, moving the cursor by 'words' should move to the first space following a
223 non-space character in the requested direction. On Windows, a 'word' includes trailing
224 whitespace, but not preceding whitespace. This means that we need a way of specifying
225 whether whitespace should be included when navigating by words.
226 */
227 static int findTextBoundary (const AccessibilityTextInterface& textInterface,
228 int currentPosition,
229 BoundaryType boundary,
230 Direction direction,
231 IncludeThisBoundary includeBoundary,
232 IncludeWhitespaceAfterWords includeWhitespace)
233 {
234 const auto numCharacters = textInterface.getTotalNumCharacters();
235 const auto isForwards = (direction == Direction::forwards);
236 const auto currentClamped = jlimit (0, numCharacters, currentPosition);
237
238 switch (boundary)
239 {
241 {
242 const auto offset = includeBoundary == IncludeThisBoundary::yes ? 0
243 : (isForwards ? 1 : -1);
244 return jlimit (0, numCharacters, currentPosition + offset);
245 }
246
248 {
249 const auto str = textInterface.getText ({ 0, numCharacters });
250 return currentClamped + findNextWordEndOffset (str.begin(),
251 str.end(),
252 str.begin() + currentClamped,
253 direction,
254 includeBoundary,
255 includeWhitespace);
256 }
257
259 {
260 const auto str = textInterface.getText ({ 0, numCharacters });
261 return currentClamped + findNextLineOffset (str.begin(),
262 str.end(),
263 str.begin() + currentClamped,
264 direction,
265 includeBoundary);
266 }
267
269 return isForwards ? numCharacters : 0;
270 }
271
273 return -1;
274 }
275
276 /* Adjusts the current text selection range, using an algorithm appropriate for cursor movement
277 on Android.
278 */
280 BoundaryType boundaryType,
281 ExtendSelection extend,
282 Direction direction)
283 {
284 const auto oldPos = textInterface.getTextInsertionOffset();
285 const auto cursorPos = findTextBoundary (textInterface,
286 oldPos,
287 boundaryType,
288 direction,
291
292 if (extend == ExtendSelection::no)
293 return { cursorPos, cursorPos };
294
295 const auto currentSelection = textInterface.getSelection();
296 const auto start = currentSelection.getStart();
297 const auto end = currentSelection.getEnd();
298 return Range<int>::between (cursorPos, oldPos == start ? end : start);
299 }
300};
301
302} // namespace juce
long rend
Definition adlibemu.c:105
Definition juce_AccessibilityTextHelpers.h:40
constexpr CharPtrIteratorAdapter & operator--()
Definition juce_AccessibilityTextHelpers.h:59
std::bidirectional_iterator_tag iterator_category
Definition juce_AccessibilityTextHelpers.h:46
value_type reference
Definition juce_AccessibilityTextHelpers.h:45
value_type * pointer
Definition juce_AccessibilityTextHelpers.h:44
constexpr CharPtrIteratorAdapter & operator++()
Definition juce_AccessibilityTextHelpers.h:53
decltype(*std::declval< CharPtr >()) value_type
Definition juce_AccessibilityTextHelpers.h:43
CharPtr ptr
Definition juce_AccessibilityTextHelpers.h:72
int difference_type
Definition juce_AccessibilityTextHelpers.h:42
constexpr auto operator*() const
Definition juce_AccessibilityTextHelpers.h:51
constexpr CharPtrIteratorAdapter(CharPtr arg)
Definition juce_AccessibilityTextHelpers.h:49
Definition juce_AccessibilityTextInterface.h:39
virtual int getTextInsertionOffset() const =0
virtual int getTotalNumCharacters() const =0
virtual String getText(Range< int > range) const =0
virtual Range< int > getSelection() const =0
static bool isWhitespace(char character) noexcept
Definition juce_CharacterFunctions.cpp:59
Definition juce_Range.h:40
static constexpr Range between(const ValueType position1, const ValueType position2) noexcept
Definition juce_Range.h:59
* e
Definition inflate.c:1404
virtual ASIOError start()=0
#define jassertfalse
Definition carla_juce.cpp:31
jack_client_t client jack_client_t client jack_client_t client jack_client_t JackInfoShutdownCallback void * arg
Definition juce_linux_JackAudio.cpp:63
@ no
Definition juce_AlertWindow.cpp:567
@ yes
Definition juce_AlertWindow.cpp:567
RangedDirectoryIterator end(const RangedDirectoryIterator &)
Definition juce_RangedDirectoryIterator.h:184
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Definition juce_MathsFunctions.h:262
wchar_t juce_wchar
Definition juce_CharacterFunctions.h:42
jack_client_t client jack_client_t client jack_client_t client jack_client_t JackInfoShutdownCallback void arg jack_client_t jack_port_t port void func jack_client_t const char const char unsigned long flags const jack_port_t port jack_client_t jack_port_id_t port_id const jack_port_t const char port_name const jack_port_t port void * ptr
Definition juce_linux_JackAudio.cpp:79
RangedDirectoryIterator begin(const RangedDirectoryIterator &it)
Definition juce_RangedDirectoryIterator.h:179
short word
Definition private.h:22
Definition juce_AccessibilityTextHelpers.h:30
BoundaryType
Definition juce_AccessibilityTextHelpers.h:82
@ line
Definition juce_AccessibilityTextHelpers.h:85
@ character
Definition juce_AccessibilityTextHelpers.h:83
@ word
Definition juce_AccessibilityTextHelpers.h:84
@ document
Definition juce_AccessibilityTextHelpers.h:86
static int findNextWordEndOffset(CharPtr beginIn, CharPtr endIn, CharPtr ptrIn, Direction direction, IncludeThisBoundary includeBoundary, IncludeWhitespaceAfterWords includeWhitespace)
Definition juce_AccessibilityTextHelpers.h:143
static int countDifference(Iter from, Iter to)
Definition juce_AccessibilityTextHelpers.h:123
ExtendSelection
Definition juce_AccessibilityTextHelpers.h:96
@ no
Definition juce_AccessibilityTextHelpers.h:97
static auto makeCharPtrIteratorAdapter(CharPtr ptr)
Definition juce_AccessibilityTextHelpers.h:76
static int findNextLineOffset(CharPtr beginIn, CharPtr endIn, CharPtr ptrIn, Direction direction, IncludeThisBoundary includeBoundary)
Definition juce_AccessibilityTextHelpers.h:187
static Range< int > findNewSelectionRangeAndroid(const AccessibilityTextInterface &textInterface, BoundaryType boundaryType, ExtendSelection extend, Direction direction)
Definition juce_AccessibilityTextHelpers.h:279
IncludeThisBoundary
Definition juce_AccessibilityTextHelpers.h:105
@ no
Definition juce_AccessibilityTextHelpers.h:106
@ yes
Definition juce_AccessibilityTextHelpers.h:107
Direction
Definition juce_AccessibilityTextHelpers.h:90
@ forwards
Definition juce_AccessibilityTextHelpers.h:91
static int findTextBoundary(const AccessibilityTextInterface &textInterface, int currentPosition, BoundaryType boundary, Direction direction, IncludeThisBoundary includeBoundary, IncludeWhitespaceAfterWords includeWhitespace)
Definition juce_AccessibilityTextHelpers.h:227
IncludeWhitespaceAfterWords
Definition juce_AccessibilityTextHelpers.h:114
@ no
Definition juce_AccessibilityTextHelpers.h:115
@ yes
Definition juce_AccessibilityTextHelpers.h:116
return c
Definition crypt.c:175
b
Definition crypt.c:628
typedef int(UZ_EXP MsgFn)()