-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
56 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,30 @@ | ||
# Anki Zoom | ||
# v1.0 3/1/2020 | ||
# v1.1 3/2/2020 | ||
# Copyright © 2020 Quip13 ([email protected]) | ||
# Based in part on code by Damien Elmes <[email protected]>, Roland Sieker <[email protected]> | ||
# Forked from https://github.com/krassowski/Anki-Zoom | ||
# Based in part on code by Damien Elmes <[email protected]>, Roland Sieker <[email protected]> and github.com/krassowski | ||
# Big thanks to u/Glutanimate and u/yumenogotoshi for code suggestions | ||
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html | ||
|
||
from aqt import * | ||
from aqt import mw | ||
from aqt.webview import AnkiWebView, QWebEngineView | ||
from aqt.qt import QEvent, Qt | ||
from anki.hooks import addHook, runHook, wrap | ||
from anki.hooks import * | ||
from anki.lang import _ | ||
|
||
zoom_step = 1.1 | ||
|
||
# After changing states, the reported mw.zoomFactor() is inaccurate | ||
# When changing states, the zoom value (Z) is applied twice, essential applying a Z^2 zoom | ||
# This value tracks the correct zoom displayed | ||
zoomActual = 1 | ||
|
||
# Reflects the desired actual zoom level (what the user expects to see). | ||
# Will deviate from zoomActual during state changes, and used to apply zoom correction | ||
userZoomActual = 1 | ||
config = mw.addonManager.getConfig(__name__) | ||
zoom_step = config[ 'zoom_step' ] | ||
|
||
def zoom_in(step=None): | ||
if not step: | ||
step = zoom_step | ||
change_zoom(zoomActual * step) | ||
change_zoom_by(step) | ||
|
||
def zoom_out(step=None): | ||
if not step: | ||
step = zoom_step | ||
change_zoom(zoomActual / step) | ||
change_zoom_by(1 / step) | ||
|
||
def reset_zoom(state=None, *args): | ||
config = mw.addonManager.getConfig(__name__) | ||
|
@@ -44,33 +37,29 @@ def reset_zoom(state=None, *args): | |
elif state == 'review': | ||
change_zoom( config[ 'review_zoom_default' ] ) | ||
|
||
def change_zoom(desired_zoomActual, fromHook=False): | ||
global zoomActual | ||
global userZoomActual | ||
pZoom = mw.web.zoomFactor() | ||
i = desired_zoomActual/zoomActual | ||
zoomFactor = pZoom*i | ||
if zoomFactor < 0.2: #documented qt bug where zoomFactor cannot exceed 5 or 1/5 | ||
zoomFactor = 0.2 | ||
elif zoomFactor > 5: | ||
zoomFactor = 5 | ||
mw.web.setZoomFactor(zoomFactor) | ||
zoomActual = zoomActual * (mw.web.zoomFactor()/pZoom) | ||
if not fromHook: | ||
userZoomActual = zoomActual | ||
debugPrint('change_zoom, ' + str(fromHook)) | ||
def change_zoom_by(interval): | ||
currZoom = QWebEngineView.zoomFactor(mw.web) | ||
change_zoom(currZoom * interval) | ||
|
||
def change_zoom(zoom_lvl): | ||
mw.web.setZoomFactor(zoom_lvl) | ||
|
||
def set_save_zoom(new_state, old_state, *args): | ||
def unpause(): | ||
mw.setUpdatesEnabled(True) | ||
|
||
mw.setUpdatesEnabled(False) | ||
old_state_zoom = QWebEngineView.zoomFactor(mw.web) | ||
if old_state == new_state: #skips if reset | ||
return | ||
config = mw.addonManager.getConfig(__name__) | ||
|
||
if old_state == 'deckBrowser': | ||
config[ 'deckBrowser_zoom' ] = userZoomActual | ||
config[ 'deckBrowser_zoom' ] = old_state_zoom | ||
elif old_state == 'overview': | ||
config[ 'overview_zoom' ] = userZoomActual | ||
config[ 'overview_zoom' ] = old_state_zoom | ||
elif old_state == 'review': | ||
config[ 'review_zoom' ] = userZoomActual | ||
config[ 'review_zoom' ] = old_state_zoom | ||
mw.addonManager.writeConfig(__name__, config) | ||
|
||
config = mw.addonManager.getConfig(__name__) | ||
|
@@ -81,81 +70,30 @@ def set_save_zoom(new_state, old_state, *args): | |
elif new_state == 'review': | ||
change_zoom( config[ 'review_zoom' ] ) | ||
|
||
resetSentByZoom = False | ||
def zoomStateChange(new_state, old_state, *args): | ||
global resetSentByZoom | ||
global zoomActual | ||
global userZoomActual | ||
QTimer.singleShot(150, unpause) #prevents flickering | ||
|
||
def unpause(): | ||
mw.setUpdatesEnabled(True) | ||
numDeg = 0 | ||
def AnkiWebView_eventFilter_wrapper(self, obj, event): | ||
global numDeg | ||
global zoom_step | ||
|
||
if old_state == 'startup': | ||
return | ||
config = mw.addonManager.getConfig(__name__) #can be moved out of func for performance but config will not update automatically | ||
scrl_threshold = config[ 'scroll_sensitivity' ] | ||
zoom_step = config[ 'zoom_step' ] | ||
|
||
if resetSentByZoom: | ||
resetSentByZoom = False | ||
QTimer.singleShot(150, unpause) #prevents flickering | ||
return | ||
elif abs(userZoomActual-zoomActual)>0.001: #does not refresh if close enough | ||
mw.setUpdatesEnabled(False) | ||
mw.web.setZoomFactor(userZoomActual**0.5) | ||
resetSentByZoom = True | ||
mw.reset() #recursion | ||
|
||
prevZoom = mw.web.zoomFactor() | ||
def calcActualZoom(new_state, old_state, *args): | ||
global zoomActual | ||
global prevZoom | ||
global currZoom | ||
if old_state == 'startup': | ||
return | ||
currZoom = mw.web.zoomFactor() | ||
if currZoom != prevZoom: | ||
zoomActual = currZoom**2 | ||
prevZoom = currZoom | ||
debugPrint('After Statechange') | ||
|
||
def debugPrint(debug=""): | ||
#print(debug + ': ZoomValue: ' + f'{mw.web.zoomFactor():.3f}' + ' Actual: ' + f'{zoomActual:.3f}' + ' UserActual: ' + f'{userZoomActual:.3f}') | ||
return | ||
|
||
# Uses QtEventListener to track wheel | ||
class wheelListener(QObject): | ||
def __init__(self): | ||
QObject.__init__(self) | ||
self.ctrl_Pushed = False | ||
self.numDeg = 0 | ||
def eventFilter(self, obj, event): | ||
if event.type() == QEvent.Wheel and self.ctrl_Pushed: | ||
self.numDeg = self.numDeg + event.angleDelta().y() | ||
if self.numDeg > 110: | ||
zoom_in() | ||
self.numDeg = 0 | ||
elif self.numDeg < -110: | ||
zoom_out() | ||
self.numDeg = 0 | ||
elif event.type() == QEvent.KeyPress and event.key() == Qt.Key_Control: | ||
self.ctrl_Pushed = True | ||
elif event.type() == QEvent.KeyRelease and event.key() == Qt.Key_Control: | ||
self.ctrl_Pushed = False | ||
return False | ||
wheelListener = wheelListener() | ||
|
||
#enables scrolling regardless of what has focus (listener installed on bottom, toolbar and main screen) | ||
def setup_event_filters(new_state, old_state, *args): #if called before startup will throw error on linux machines | ||
if old_state == 'startup': | ||
reviewer_QWidget = mw.reviewer.web.findChildren(QWidget)[0] #undocumented method to get underlying event-handling widget of QWebView *may break in future Qt releases | ||
reviewer_QWidget.installEventFilter(wheelListener) | ||
|
||
bottom_QWidget = mw.reviewer.bottom.web.findChildren(QWidget)[0] #undocumented method to get underlying event-handling widget of QWebView *may break in future Qt releases | ||
bottom_QWidget.installEventFilter(wheelListener) | ||
|
||
toolbar_QWidget = mw.toolbar.web.findChildren(QWidget)[0] #undocumented method to get underlying event-handling widget of QWebView *may break in future Qt releases | ||
toolbar_QWidget.installEventFilter(wheelListener) | ||
if (mw.app.keyboardModifiers() == Qt.ControlModifier and | ||
event.type() == QEvent.Wheel): | ||
numDeg = numDeg + event.angleDelta().y() | ||
if numDeg > scrl_threshold: | ||
zoom_in() | ||
numDeg = 0 | ||
elif numDeg < -scrl_threshold : | ||
zoom_out() | ||
numDeg = 0 | ||
|
||
AnkiWebView.eventFilter = wrap(AnkiWebView.eventFilter, AnkiWebView_eventFilter_wrapper, 'before') | ||
|
||
def add_action(submenu, label, callback, shortcut=None): | ||
"""Add action to menu""" | ||
action = QAction(_(label), mw) | ||
action.triggered.connect(callback) | ||
if shortcut: | ||
|
@@ -167,7 +105,6 @@ def add_action(submenu, label, callback, shortcut=None): | |
return action | ||
|
||
def setup_menu(): | ||
"""Set up the zoom menu.""" | ||
try: | ||
mw.addon_view_menu | ||
except AttributeError: | ||
|
@@ -183,21 +120,8 @@ def setup_menu(): | |
add_action(mw.zoom_submenu, 'Zoom &In', zoom_in, ['Ctrl++','Ctrl+=']) | ||
add_action(mw.zoom_submenu, 'Zoom &Out', zoom_out, ['Ctrl+-']) | ||
mw.zoom_submenu.addSeparator() | ||
|
||
add_action(mw.zoom_submenu, '&Reset', reset_zoom, ['Ctrl+0']) | ||
|
||
def real_zoom_factor(self): | ||
"""Use the default zoomFactor. | ||
Overwrites Anki's effort to support hiDPI screens. | ||
""" | ||
return QWebEngineView.zoomFactor(self) | ||
|
||
AnkiWebView.zoomFactor = real_zoom_factor | ||
|
||
addHook("afterStateChange", calcActualZoom) | ||
addHook("afterStateChange", zoomStateChange) | ||
addHook("afterStateChange", set_save_zoom) | ||
addHook("afterStateChange", setup_event_filters) | ||
|
||
setup_menu() | ||
setup_menu() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,15 @@ | ||
### Anki Zoom v1.0 Config: | ||
### Anki Zoom v1.1 Config: | ||
All config is effective immediately | ||
|
||
- `deckBrowser_zoom_default`: Zoom level that the reset button applies for the deck browser | ||
|
||
- `overview_zoom_default`: Zoom level that the reset button applies for the overview screen (screen after selecting a deck) | ||
|
||
- `review_zoom_default`: Zoom level that the reset button applies for card reviews | ||
|
||
- `deckBrowser_zoom_default`: Zoom level that the reset button applies for the deck browser | ||
- `zoom_step`: How much is zoom is applied per step. | ||
Values are a percentage: e.g. `1.1` = 110% scaling on zoom in, (1/1.1)≈91% scaling on zoom out | ||
<u>To invert zoom, enter values <1</u> | ||
|
||
- `scroll_sensitivity`: Defines how much scrolling triggers a zoom step (in arbitrary units). Lower values correlate to more sensitive scrolling. | ||
For reference, mousewheels typically emit 120 units per click. High resolution trackpads (Mac + Windows Precision Touchpads) produce a range of values depending on your movement. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.