Skip to content

Commit 8b9c773

Browse files
authored
changes magnifier types and function name for clarity (#19882)
pre - #19473 parts of #19810 Summary of the issue: #19810 was still to big so I focused on types changes and some functions renaming to go accordingly. All these changes are nescessary for futur magnifier implementations. Description of user facing changes: "default"s have been removed so it can be seen in the doc Description of developer facing changes: replaced MagnifierPosition with MagnifierParameters for better handling of size, place and filter of the magnifier. added a MagnifierType to handle magnifiers different types. Description of development approach: This work was split out from PR #19473 to make review and integration easier. We first added the new structure: MagnifierParameters for size/position/filter, and MagnifierType for futur mode switching.
1 parent b9d7f0a commit 8b9c773

11 files changed

Lines changed: 223 additions & 219 deletions

File tree

source/_magnifier/commands.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
import ui
1313
from . import getMagnifier, initialize, terminate
1414
from .config import (
15-
getDefaultZoomLevelString,
16-
getDefaultFilter,
17-
getDefaultFullscreenMode,
15+
getZoomLevelString,
16+
getFilter,
17+
getFullscreenMode,
1818
ZoomLevel,
1919
getFollowState,
2020
setFollowState,
@@ -104,16 +104,16 @@ def toggleMagnifier() -> None:
104104
else:
105105
initialize()
106106

107-
filter = getDefaultFilter()
108-
fullscreenMode = getDefaultFullscreenMode()
107+
filter = getFilter()
108+
fullscreenMode = getFullscreenMode()
109109

110110
ui.message(
111111
pgettext(
112112
"magnifier",
113113
# Translators: Message announced when starting the NVDA magnifier.
114114
"Starting magnifier with {zoomLevel} zoom level, {filter} filter, and {fullscreenMode} full-screen mode",
115115
).format(
116-
zoomLevel=getDefaultZoomLevelString(),
116+
zoomLevel=getZoomLevelString(),
117117
filter=filter.displayString,
118118
fullscreenMode=fullscreenMode.displayString,
119119
),

source/_magnifier/config.py

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -50,72 +50,75 @@ def zoom_strings(cls) -> list[str]:
5050
]
5151

5252

53-
def getDefaultZoomLevel() -> float:
53+
def getZoomLevel() -> float:
5454
"""
55-
Get default zoom level from config.
55+
Get zoom level from config.
5656
57-
:return: The default zoom level.
57+
:return: The zoom level.
5858
"""
59-
zoomLevel = config.conf["magnifier"]["defaultZoomLevel"]
59+
zoomLevel = config.conf["magnifier"]["zoomLevel"]
6060
return zoomLevel
6161

6262

63-
def getDefaultZoomLevelString() -> str:
63+
def getZoomLevelString() -> str:
6464
"""
65-
Get default zoom level as a formatted string.
65+
Get zoom level as a formatted string.
6666
6767
:return: Formatted zoom level string.
6868
"""
69-
zoomLevel = getDefaultZoomLevel()
69+
zoomLevel = getZoomLevel()
7070
zoomValues = ZoomLevel.zoom_range()
7171
zoomStrings = ZoomLevel.zoom_strings()
72-
zoomIndex = zoomValues.index(zoomLevel)
73-
return zoomStrings[zoomIndex]
72+
closestIndex = min(
73+
range(len(zoomValues)),
74+
key=lambda i: abs(zoomValues[i] - zoomLevel),
75+
)
76+
return zoomStrings[closestIndex]
7477

7578

76-
def setDefaultZoomLevel(zoomLevel: float) -> None:
79+
def setZoomLevel(zoomLevel: float) -> None:
7780
"""
78-
Set default zoom level from settings.
81+
Set zoom level from settings.
7982
8083
:param zoomLevel: The zoom level to set.
8184
"""
82-
config.conf["magnifier"]["defaultZoomLevel"] = zoomLevel
85+
config.conf["magnifier"]["zoomLevel"] = zoomLevel
8386

8487

85-
def getDefaultPanStep() -> int:
88+
def getPanStep() -> int:
8689
"""
87-
Get default pan value from config.
90+
Get pan value from config.
8891
89-
:return: The default pan value.
92+
:return: The pan value.
9093
"""
91-
return config.conf["magnifier"]["defaultPanStep"]
94+
return config.conf["magnifier"]["panStep"]
9295

9396

94-
def setDefaultPanStep(panStep: int) -> None:
97+
def setPanStep(panStep: int) -> None:
9598
"""
96-
Set default pan value from settings.
99+
Set pan value from settings.
97100
98101
:param panStep: The pan value to set.
99102
"""
100-
config.conf["magnifier"]["defaultPanStep"] = panStep
103+
config.conf["magnifier"]["panStep"] = panStep
101104

102105

103-
def getDefaultFilter() -> Filter:
106+
def getFilter() -> Filter:
104107
"""
105-
Get default filter from config.
108+
Get filter from config.
106109
107-
:return: The default filter.
110+
:return: The filter.
108111
"""
109-
return Filter(config.conf["magnifier"]["defaultFilter"])
112+
return Filter(config.conf["magnifier"]["filter"])
110113

111114

112-
def setDefaultFilter(filter: Filter) -> None:
115+
def setFilter(filter: Filter) -> None:
113116
"""
114-
Set default filter from settings.
117+
Set filter from settings.
115118
116119
:param filter: The filter to set.
117120
"""
118-
config.conf["magnifier"]["defaultFilter"] = filter.value
121+
config.conf["magnifier"]["filter"] = filter.value
119122

120123

121124
_FOLLOW_CONFIG_KEYS: dict[MagnifierFollowFocusType, str] = {
@@ -223,3 +226,21 @@ def shouldKeepMouseCentered() -> bool:
223226
:return: True if mouse should be kept centered, False otherwise.
224227
"""
225228
return config.conf["magnifier"]["keepMouseCentered"]
229+
230+
231+
def getFullscreenMode() -> FullScreenMode:
232+
"""
233+
Get full-screen mode from config.
234+
235+
:return: The full-screen mode.
236+
"""
237+
return FullScreenMode(config.conf["magnifier"]["fullscreenMode"])
238+
239+
240+
def setFullscreenMode(mode: FullScreenMode) -> None:
241+
"""
242+
Set full-screen mode from settings.
243+
244+
:param mode: The full-screen mode to set.
245+
"""
246+
config.conf["magnifier"]["fullscreenMode"] = mode.value

source/_magnifier/fullscreenMagnifier.py

Lines changed: 65 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,26 @@
1515
from .magnifier import Magnifier
1616
from .utils.filterHandler import FilterMatrix
1717
from .utils.spotlightManager import SpotlightManager
18-
from .utils.types import Filter, Coordinates, FullScreenMode
19-
from .config import getDefaultFullscreenMode
18+
from .utils.types import (
19+
Filter,
20+
MagnifierType,
21+
FullScreenMode,
22+
Size,
23+
MagnifierParameters,
24+
Coordinates,
25+
)
26+
from .config import getFullscreenMode, isTrueCentered
2027
from .utils.errorHandling import trackNativeMagnifierErrors
2128

2229

2330
class FullScreenMagnifier(Magnifier):
2431
def __init__(self):
2532
super().__init__()
26-
self._fullscreenMode = getDefaultFullscreenMode()
33+
self._magnifierType = MagnifierType.FULLSCREEN
34+
self._fullscreenMode = getFullscreenMode()
2735
self._currentCoordinates = Coordinates(0, 0)
2836
self._spotlightManager = SpotlightManager(self)
37+
self._displaySize = Size(self._displayOrientation.width, self._displayOrientation.height)
2938
self._startMagnifier()
3039

3140
@property
@@ -193,11 +202,11 @@ def _fullscreenMagnifier(self, coordinates: Coordinates) -> None:
193202
194203
:coordinates: The (x, y) coordinates to center the magnifier on
195204
"""
196-
left, top, visibleWidth, visibleHeight = self._getMagnifierPosition(coordinates)
205+
params = self._getMagnifierParameters(coordinates)
197206
magnification.MagSetFullscreenTransform(
198207
self.zoomLevel,
199-
left,
200-
top,
208+
params.coordinates.x,
209+
params.coordinates.y,
201210
)
202211

203212
def _getCoordinatesForMode(
@@ -231,11 +240,11 @@ def _keepMouseCentered(self) -> None:
231240
):
232241
log.debug("Mouse button pressed, skipping cursor repositioning to avoid interfering with click")
233242
return
234-
coords = self._getCoordinatesForMode(self._currentCoordinates)
235-
left, top, visibleWidth, visibleHeight = self._getMagnifierPosition(coords)
236-
centerX = left + visibleWidth // 2
237-
centerY = top + visibleHeight // 2
238-
self._setCursorToCenter(centerX, centerY)
243+
coordinates = self._getCoordinatesForMode(self._currentCoordinates)
244+
params = self._getMagnifierParameters(coordinates)
245+
centerX = params.coordinates.x + params.magnifierSize.width // 2
246+
centerY = params.coordinates.y + params.magnifierSize.height // 2
247+
winUser.setCursorPos(centerX, centerY)
239248

240249
@trackNativeMagnifierErrors
241250
def _setCursorToCenter(self, x: int, y: int) -> None:
@@ -259,14 +268,16 @@ def _borderPos(
259268
:return: The adjusted position (x, y) of the focus point
260269
"""
261270
focusX, focusY = coordinates
262-
lastLeft, lastTop, visibleWidth, visibleHeight = self._getMagnifierPosition(
263-
self._lastScreenPosition,
264-
)
271+
params = self._getMagnifierParameters(self._lastScreenPosition)
272+
magnifierWidth = params.magnifierSize.width
273+
magnifierHeight = params.magnifierSize.height
274+
lastLeft = params.coordinates.x
275+
lastTop = params.coordinates.y
265276

266277
minX = lastLeft + self._MARGIN_BORDER
267-
maxX = lastLeft + visibleWidth - self._MARGIN_BORDER
278+
maxX = lastLeft + magnifierWidth - self._MARGIN_BORDER
268279
minY = lastTop + self._MARGIN_BORDER
269-
maxY = lastTop + visibleHeight - self._MARGIN_BORDER
280+
maxY = lastTop + magnifierHeight - self._MARGIN_BORDER
270281

271282
dx = 0
272283
dy = 0
@@ -283,8 +294,8 @@ def _borderPos(
283294

284295
if dx != 0 or dy != 0:
285296
return Coordinates(
286-
self._lastScreenPosition[0] + dx,
287-
self._lastScreenPosition[1] + dy,
297+
self._lastScreenPosition.x + dx,
298+
self._lastScreenPosition.y + dy,
288299
)
289300
else:
290301
return self._lastScreenPosition
@@ -304,21 +315,21 @@ def _relativePos(
304315

305316
zoom = self.zoomLevel
306317
mouseX, mouseY = coordinates
307-
visibleWidth = self._displayOrientation.width / zoom
308-
visibleHeight = self._displayOrientation.height / zoom
318+
magnifierWidth = self._displayOrientation.width / zoom
319+
magnifierHeight = self._displayOrientation.height / zoom
309320
margin = int(zoom * 10)
310321

311322
# Calculate left/top maintaining mouse relative position
312-
left = mouseX - (mouseX / self._displayOrientation.width) * (visibleWidth - margin)
313-
top = mouseY - (mouseY / self._displayOrientation.height) * (visibleHeight - margin)
323+
left = mouseX - (mouseX / self._displayOrientation.width) * (magnifierWidth - margin)
324+
top = mouseY - (mouseY / self._displayOrientation.height) * (magnifierHeight - margin)
314325

315326
# Clamp to screen boundaries
316-
left = max(0, min(left, self._displayOrientation.width - visibleWidth))
317-
top = max(0, min(top, self._displayOrientation.height - visibleHeight))
327+
left = max(0, min(left, self._displayOrientation.width - magnifierWidth))
328+
top = max(0, min(top, self._displayOrientation.height - magnifierHeight))
318329

319330
# Return center of zoom window
320-
centerX = int(left + visibleWidth / 2)
321-
centerY = int(top + visibleHeight / 2)
331+
centerX = int(left + magnifierWidth / 2)
332+
centerY = int(top + magnifierHeight / 2)
322333
self._lastScreenPosition = Coordinates(centerX, centerY)
323334
return self._lastScreenPosition
324335

@@ -338,3 +349,31 @@ def _stopSpotlight(self) -> None:
338349
"""
339350
self._spotlightManager._spotlightIsActive = False
340351
self._startTimer(self._updateMagnifier)
352+
353+
def _getMagnifierParameters(self, coordinates: Coordinates) -> MagnifierParameters:
354+
"""
355+
Compute the top-left corner of the magnifier window centered on (x, y)
356+
357+
:param coordinates: The (x, y) coordinates to center the magnifier on
358+
359+
:return: The size, position and filter of the magnifier window
360+
"""
361+
x, y = coordinates
362+
# Calculate the size of the capture area at the current zoom level
363+
magnifierWidth = self._displayOrientation.width / self.zoomLevel
364+
magnifierHeight = self._displayOrientation.height / self.zoomLevel
365+
366+
# Compute the top-left corner so that (x, y) is at the center
367+
left = int(x - (magnifierWidth / 2))
368+
top = int(y - (magnifierHeight / 2))
369+
370+
# Clamp to screen boundaries only if not in true center mode
371+
if not isTrueCentered():
372+
left = max(0, min(left, int(self._displayOrientation.width - magnifierWidth)))
373+
top = max(0, min(top, int(self._displayOrientation.height - magnifierHeight)))
374+
375+
return MagnifierParameters(
376+
Size(int(magnifierWidth), int(magnifierHeight)),
377+
Coordinates(left, top),
378+
self._filterType,
379+
)

source/_magnifier/magnifier.py

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@
1919
from winAPI import _displayTracking
2020
from winAPI._displayTracking import OrientationState, getPrimaryDisplayOrientation
2121
from .utils.types import (
22-
MagnifierPosition,
22+
MagnifierParameters,
2323
MagnifierAction,
24-
Coordinates,
2524
MagnifierType,
2625
Direction,
2726
Filter,
27+
Coordinates,
2828
)
2929
from .config import (
30-
getDefaultZoomLevel,
31-
getDefaultPanStep,
32-
getDefaultFilter,
30+
getZoomLevel,
31+
getPanStep,
32+
getFilter,
3333
ZoomLevel,
3434
isTrueCentered,
3535
shouldKeepMouseCentered,
@@ -43,16 +43,16 @@ class Magnifier:
4343

4444
def __init__(self):
4545
self._displayOrientation = getPrimaryDisplayOrientation()
46-
self._magnifierType: MagnifierType = MagnifierType.FULLSCREEN
46+
self._magnifierType: MagnifierType
4747
self._isActive: bool = False
48-
self._zoomLevel: float = getDefaultZoomLevel()
49-
self._panStep: int = getDefaultPanStep()
48+
self._zoomLevel: float = getZoomLevel()
49+
self._panStep: int = getPanStep()
5050
self._timer: None | wx.Timer = None
5151
self._focusManager = FocusManager()
5252
self._lastScreenPosition = Coordinates(0, 0)
5353
self._currentCoordinates = Coordinates(0, 0)
5454
self._lastFocusCoordinates = Coordinates(0, 0)
55-
self._filterType: Filter = getDefaultFilter()
55+
self._filterType: Filter = getFilter()
5656
self._isManualPanning: bool = False
5757
self._consecutiveErrors: int = 0
5858
# Register for display changes
@@ -343,29 +343,12 @@ def _stopTimer(self) -> None:
343343
else:
344344
log.debug("no timer to stop")
345345

346-
def _getMagnifierPosition(
347-
self,
348-
coordinates: Coordinates,
349-
) -> MagnifierPosition:
346+
def _getMagnifierParameters(self, coordinates: Coordinates) -> MagnifierParameters:
350347
"""
351348
Compute the top-left corner of the magnifier window centered on (x, y)
352349
353350
:param coordinates: The (x, y) coordinates to center the magnifier on
354351
355-
:return: The position and size of the magnifier window
352+
:return: The size, position and filter of the magnifier window
356353
"""
357-
x, y = coordinates
358-
# Calculate the size of the capture area at the current zoom level
359-
visibleWidth = self._displayOrientation.width / self.zoomLevel
360-
visibleHeight = self._displayOrientation.height / self.zoomLevel
361-
362-
# Compute the top-left corner so that (x, y) is at the center
363-
left = int(x - (visibleWidth / 2))
364-
top = int(y - (visibleHeight / 2))
365-
366-
# Clamp to screen boundaries only if not in true center mode
367-
if not isTrueCentered():
368-
left = max(0, min(left, int(self._displayOrientation.width - visibleWidth)))
369-
top = max(0, min(top, int(self._displayOrientation.height - visibleHeight)))
370-
371-
return MagnifierPosition(left, top, int(visibleWidth), int(visibleHeight))
354+
raise NotImplementedError("Subclasses must implement this method")

0 commit comments

Comments
 (0)