Allow the review cursor to be bounded to onscreen text#9735
Allow the review cursor to be bounded to onscreen text#9735codeofdusk wants to merge 31 commits intonvaccess:masterfrom
Conversation
…nd the console by default to maintain previous behavior.
|
Are you aware of how first visible oand last visible offsets are implemented in textInfos.offsets? Given your initial description, I really like this new approach, but it makes sense to implement this for offsets textInfos as well. Note that you can utilize locationHelper to implement an abstract version of |
|
@LeonarddeR I've added a basic implementation for |
source/NVDAObjects/__init__.py
Outdated
| category=_(u"Text review"), | ||
| # Translators: A gesture description. | ||
| description=_(u"Toggles whether review is constrained to the currently visible text")) | ||
| def script_toggleReviewBounds(self, gesture): |
There was a problem hiding this comment.
It worries me that this is is on the object instead of a global command. Is there a particular reason for that?
There was a problem hiding this comment.
I too think this could be cleaner as a global command, but the reviewBounded variable is also on the object so keeping this there might be better from an organizational standpoint...
There was a problem hiding this comment.
Question is whether we really believe that review Bounded should be on the object or on the textInfo, or even global. If an object gets destroyed and created again, the state of review Bounded is lost. Having review bounds on tree interceptors also makes sense, i.e. when you want to review with document review what is on screen on a particular page.
I also think that it doesn't make much sense to have review bounds doing anything when in screen review. So in that case, the command should just do nothing.
There was a problem hiding this comment.
I think it may have been my idea to put this on the object. but @LeonarddeR brings up a good point in that the state will be lost if moving away from the object and back again. The problem with having it global though is that different controls work best when reviewBounded is set in a specific way by default. I.e. consoles probably want it on by default.
Would we be comfortable having bounded on by default globally? I think this could work, but it would be a bit of a change to NvDA's behaviour. Probably a good change though. Thoughts?
There was a problem hiding this comment.
Yes, having this as a global default makes sense to me.
There was a problem hiding this comment.
Yes, I also think a global default would be a plus.
It does not make much sense for a "screen" review to easily review what's not on screen.
It can be helpful at times, but is most often confusing when collaborating with a sighted person.
There was a problem hiding this comment.
This has now been made a global default.
Co-Authored-By: Leonard de Ruijter <[email protected]>
source/NVDAObjects/__init__.py
Outdated
| category=_(u"Text review"), | ||
| # Translators: A gesture description. | ||
| description=_(u"Toggles whether review is constrained to the currently visible text")) | ||
| def script_toggleReviewBounds(self, gesture): |
There was a problem hiding this comment.
I think it may have been my idea to put this on the object. but @LeonarddeR brings up a good point in that the state will be lost if moving away from the object and back again. The problem with having it global though is that different controls work best when reviewBounded is set in a specific way by default. I.e. consoles probably want it on by default.
Would we be comfortable having bounded on by default globally? I think this could work, but it would be a bit of a change to NvDA's behaviour. Probably a good change though. Thoughts?
source/NVDAObjects/__init__.py
Outdated
| description=_(u"Toggles whether review is constrained to the currently visible text")) | ||
| def script_toggleReviewBounds(self, gesture): | ||
| try: | ||
| rp = api.getReviewPosition() |
There was a problem hiding this comment.
This line should be moved above the try block. Only isOffscreen is expected to throw NotImplementedError.
source/NVDAObjects/__init__.py
Outdated
| ) | ||
| if outOfBounds: | ||
| api.setReviewPosition( | ||
| self.makeTextInfo(textInfos.POSITION_CARET), isCaret=True) |
There was a problem hiding this comment.
Can you explain why isCaret=True is necessary here?
There was a problem hiding this comment.
Because the textInfo is a caret instance? Maybe it isn't needed...
source/NVDAObjects/UIA/__init__.py
Outdated
| try: | ||
| visiRanges = self.obj.UIATextPattern.GetVisibleRanges() | ||
| element = 0 if position == textInfos.POSITION_FIRSTVISIBLE else visiRanges.length - 1 | ||
| self._rangeObj = visiRanges.GetElement(0) |
There was a problem hiding this comment.
This call should use element, not 0 I think.
source/NVDAObjects/UIA/__init__.py
Outdated
| element = 0 if position == textInfos.POSITION_FIRSTVISIBLE else visiRanges.length - 1 | ||
| self._rangeObj = visiRanges.GetElement(0) | ||
| except COMError: | ||
| # Error: FIRST_VISIBLE position not supported by the UIA text pattern. |
There was a problem hiding this comment.
The comment should reflect it is first or last position not supported, not just first.
source/NVDAObjects/UIA/__init__.py
Outdated
| UIAHandler.TextPatternRangeEndpoint_End) >= 0 | ||
| else: | ||
| # Review bounds not available. | ||
| return super(UIATextInfo, self).isOutOfBounds() |
There was a problem hiding this comment.
I think this is supposed to be super's isOffscreen
source/NVDAObjects/UIA/__init__.py
Outdated
| return self._rangeObj.CompareEndpoints(src,other._rangeObj,target) | ||
|
|
||
| def isOffscreen(self): | ||
| visiRanges = self.obj.UIATextPattern.GetVisibleRanges() |
There was a problem hiding this comment.
Catch COMError around this call, raising NotImplementedError if so.
| script_review_activate.__doc__=_("Performs the default action on the current navigator object (example: presses it if it is a button).") | ||
| script_review_activate.category=SCRCAT_OBJECTNAVIGATION | ||
|
|
||
| def _moveWithBoundsChecking(self, info, unit, direction, endPoint=None): |
There was a problem hiding this comment.
This could probably be moved into the base TextInfo class.
Also, is there a reason why this is non-distructive (I.e. returns a copy)? I don't think you actually ever make use of this. It could just do it distructively and return res like the other move... unless you have a particular plan for this not yet done?
There was a problem hiding this comment.
This is a generalization of the console's old bounds checking code (i.e. we captured an oldRange and didn't update the underlying UIA text range if a move was impossible). Would destructive be okay here?
|
"@param isCaret: Whether the review position is changed due to caret
following.".
I don't think you need it. This should only be true if the
setReviewPosition call is directly caused by the caret moving.
|
|
Unless I've missed a call when reviewing, It looks like
_moveWithBoundsChecking only ever directly replaces a call to info.move,
and always overrides info.
|
Yes, we can do this, because the original |
|
@michaelDCurran @LeonarddeR This PR now uses unique IDs for NVDA objects to persist review bounds states when objects are regenerated. I'd like to move the logic that sets I'd also like to move |
|
NVDAObject overlay classes don't support the standard |
|
Currently TextContainerObject does not inherit from ScriptableObject and therefore scripts are not picked up if placed on this class. To |
@michaelDCurran Working now, thanks! |
|
|
||
| def _get_isOffscreen(self): | ||
| """ | ||
| Returns True if this textInfo is positioned outside its object's |
There was a problem hiding this comment.
If the text is partially visible, what is returned?
There was a problem hiding this comment.
Depends on the underlying implementation.
…ls and disable the console bounds checking code when oldRange is also offscreen.
|
Superseded for now by #9957, but I'm willing to look into this again if there's a use case. |
…e checks (PR #9957) Builds on #9614 Supersedes #9735 and #9899 Closes #9891 Previously, after the console window was maximized (or the review cursor is otherwise placed outside the visible text), text review is no longer functional. The review top line and review bottom line scripts do not function as intended. This commit changes: - The isOffscreen property has been implemented as UIAUtils.isTextRangeOffscreen. - When checking if the text range is out of bounds, we now also check that oldRange is in bounds before stopping movement. - Re-implemented POSITION_FIRST and POSITION_LAST in terms of visible ranges.
…ls and disable the console bounds checking code when oldRange is also offscreen.
This reverts commit 9fbd6b4.
Link to issue number:
Builds on #9614. Supersedes #9687 and #9899. Closes #9891.
Summary of the issue:
Currently:
Description of how this pull request fixes the issue:
This PR adds new functionality to
textInfoobjects: anisOffscreenproperty andPOSITION_FIRSTVISIBLEandPOSITION_LASTVISIBLEposition constants. A new script (bound to NVDA+o by default) toggles review bounds. Review is bounded by default where supported. An implementation of review bounds has been provided for UIA (primarily intended for use in the console) andoffsetsTextInfo.Testing performed:
Attempted to review text before and after running
git login the UIA console using bounded and unbounded modes on Windows 10 1903. Verified that when review is bounded, reviewing the top/bottom lines (shift+numpad 7/9) works as intended.Known issues with pull request:
Change log entry:
== New Features ==
== Changes for Developers ==
textInfoobjects by implementing the newisOffscreenproperty andPOSITION_FIRSTVISIBLEandPOSITION_LASTVISIBLEpositions. Refer to the implementations inUIATextInfoandoffsetsTextInfo. (Allow the review cursor to be bounded to onscreen text #9735)scriptCategoriesmodule. These constants are also available inglobalCommandsandinputCoreas before to avoid breaking existing code. (Allow the review cursor to be bounded to onscreen text #9735)