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

Ensure settings are scrolled to using tab navigation #12300

Merged
merged 9 commits into from
Apr 21, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
75 changes: 67 additions & 8 deletions source/gui/nvdaControls.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
# -*- coding: UTF-8 -*-
#A part of NonVisual Desktop Access (NVDA)
#Copyright (C) 2016-2018 NV Access Limited, Derek Riemer
#This file is covered by the GNU General Public License.
#See the file COPYING for more details.
# A part of NonVisual Desktop Access (NVDA)
# Copyright (C) 2016-2021 NV Access Limited, Derek Riemer
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

from ctypes.wintypes import BOOL
from typing import Any, Tuple, Optional
import wx
from comtypes import GUID
from wx.lib import scrolledpanel
from wx.lib.mixins import listctrl as listmix
from .dpiScalingHelper import DpiScalingHelperMixin
from . import guiHelper
import oleacc
import winUser
import winsound
import math

from collections.abc import Callable

class AutoWidthColumnListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
Expand Down Expand Up @@ -355,3 +354,63 @@ def onSliderChar(self, evt):
evt.Skip()
return
self.SetValue(newValue)


class TabbableScrolledPanel(scrolledpanel.ScrolledPanel):
"""
This class was created to ensure a ScrolledPanel scrolls to nested children of the panel when navigating
with tabs (#12224). A PR to wxPython implementing this fix can be tracked on
https://github.com/wxWidgets/Phoenix/pull/1950
"""
def GetChildRectRelativeToSelf(self, child: wx.Window) -> wx.Rect:
"""
window.GetRect returns the size of a window, and its position relative to its parent.
When calculating ScrollChildIntoView, the position relative to its parent is not relevant unless the
parent is the ScrolledPanel itself. Instead, calculate the position relative to scrolledPanel
"""
cr = child.GetScreenRect()
spr = self.GetScreenPosition()
return wx.Rect(cr.x - spr.x, cr.y - spr.y, cr.width, cr.height)

def ScrollChildIntoView(self, child: wx.Window) -> None:
"""
Uses the same logic as super().ScrollChildIntoView(self, child)
except cr = self.GetChildRectRelativeToSelf(child) instead of cr = GetRect()
"""
sppu_x, sppu_y = self.GetScrollPixelsPerUnit()
vs_x, vs_y = self.GetViewStart()
cr = self.GetChildRectRelativeToSelf(child)
clntsz = self.GetClientSize()
new_vs_x, new_vs_y = -1, -1
Copy link
Contributor

Choose a reason for hiding this comment

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

I would love it if there was a way to avoid having to duplicate the majority of this function.

Copy link
Member Author

Choose a reason for hiding this comment

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

how does this new logic look? I am not a fan of overriding this function but it makes the actual change that we are doing clearer.


# is it before the left edge?
if cr.x < 0 and sppu_x > 0:
new_vs_x = vs_x + (cr.x / sppu_x)

# is it above the top?
if cr.y < 0 and sppu_y > 0:
new_vs_y = vs_y + (cr.y / sppu_y)

# For the right and bottom edges, scroll enough to show the
# whole control if possible, but if not just scroll such that
# the top/left edges are still visible

# is it past the right edge ?
if cr.right > clntsz.width and sppu_x > 0:
diff = math.ceil(1.0 * (cr.right - clntsz.width + 1) / sppu_x)
if cr.x - diff * sppu_x > 0:
new_vs_x = vs_x + diff
else:
new_vs_x = vs_x + (cr.x / sppu_x)

# is it below the bottom ?
if cr.bottom > clntsz.height and sppu_y > 0:
diff = math.ceil(1.0 * (cr.bottom - clntsz.height + 1) / sppu_y)
if cr.y - diff * sppu_y > 0:
new_vs_y = vs_y + diff
else:
new_vs_y = vs_y + (cr.y / sppu_y)

# if we need to adjust
if new_vs_x != -1 or new_vs_y != -1:
self.Scroll(new_vs_x, new_vs_y)
3 changes: 1 addition & 2 deletions source/gui/settingsDialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import typing
import wx
from vision.providerBase import VisionEnhancementProviderSettings
from wx.lib import scrolledpanel
from wx.lib.expando import ExpandoTextCtrl
import wx.lib.newevent
import winUser
Expand Down Expand Up @@ -483,7 +482,7 @@ def makeSettings(self, settingsSizer):
# The provided column header is just a placeholder, as it is hidden due to the wx.LC_NO_HEADER style flag.
self.catListCtrl.InsertColumn(0,categoriesLabelText)

self.container = scrolledpanel.ScrolledPanel(
self.container = nvdaControls.TabbableScrolledPanel(
parent = self,
style = wx.TAB_TRAVERSAL | wx.BORDER_THEME,
size=containerDim
Expand Down