First steps at getting rid of signal cache
This commit is contained in:
parent
0d104b5813
commit
d3eaeaac91
@ -397,14 +397,17 @@ class QuteBrowser(QApplication):
|
|||||||
self.config.changed.connect(obj.on_config_changed)
|
self.config.changed.connect(obj.on_config_changed)
|
||||||
|
|
||||||
# statusbar
|
# statusbar
|
||||||
|
tabs.currentChanged.connect(status.prog.current_changed)
|
||||||
tabs.cur_progress.connect(status.prog.setValue)
|
tabs.cur_progress.connect(status.prog.setValue)
|
||||||
tabs.cur_load_finished.connect(status.prog.hide)
|
tabs.cur_load_finished.connect(status.prog.hide)
|
||||||
tabs.cur_load_started.connect(status.url.on_loading_started)
|
|
||||||
tabs.cur_load_finished.connect(status.url.on_loading_finished)
|
|
||||||
tabs.cur_ssl_errors.connect(status.url.on_ssl_errors)
|
|
||||||
tabs.cur_load_started.connect(status.prog.on_load_started)
|
tabs.cur_load_started.connect(status.prog.on_load_started)
|
||||||
|
|
||||||
|
tabs.currentChanged.connect(status.percentage.current_changed)
|
||||||
tabs.cur_scroll_perc_changed.connect(status.percentage.set_perc)
|
tabs.cur_scroll_perc_changed.connect(status.percentage.set_perc)
|
||||||
|
|
||||||
tabs.cur_statusbar_message.connect(status.txt.on_statusbar_message)
|
tabs.cur_statusbar_message.connect(status.txt.on_statusbar_message)
|
||||||
|
|
||||||
|
tabs.currentChanged.connect(status.url.current_changed)
|
||||||
tabs.cur_url_changed.connect(status.url.set_url)
|
tabs.cur_url_changed.connect(status.url.set_url)
|
||||||
tabs.cur_link_hovered.connect(status.url.set_hover_url)
|
tabs.cur_link_hovered.connect(status.url.set_hover_url)
|
||||||
|
|
||||||
|
@ -61,9 +61,6 @@ class SignalFilter(QObject):
|
|||||||
The original signal does not matter, since we get the new signal and
|
The original signal does not matter, since we get the new signal and
|
||||||
all args.
|
all args.
|
||||||
|
|
||||||
The current value of the signal is also stored in tab.signal_cache so
|
|
||||||
it can be emitted later when the tab changes to the current tab.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
signal: The signal to emit if the sender was the current widget.
|
signal: The signal to emit if the sender was the current widget.
|
||||||
*args: The args to pass to the signal.
|
*args: The args to pass to the signal.
|
||||||
@ -81,7 +78,6 @@ class SignalFilter(QObject):
|
|||||||
logging.warn("Got signal {} by {} which is no tab!".format(
|
logging.warn("Got signal {} by {} which is no tab!".format(
|
||||||
dbg_signal(signal, args), sender))
|
dbg_signal(signal, args), sender))
|
||||||
return
|
return
|
||||||
sender.signal_cache.add(signal, args)
|
|
||||||
if self._tabs.currentWidget() == sender:
|
if self._tabs.currentWidget() == sender:
|
||||||
if log_signal:
|
if log_signal:
|
||||||
logging.debug(" emitting")
|
logging.debug(" emitting")
|
||||||
|
@ -32,7 +32,6 @@ class FakeSignal:
|
|||||||
|
|
||||||
def __init__(self, name='fake'):
|
def __init__(self, name='fake'):
|
||||||
self.signal = '2{}(int, int)'.format(name)
|
self.signal = '2{}(int, int)'.format(name)
|
||||||
self.emit = Mock()
|
|
||||||
|
|
||||||
|
|
||||||
class TestDebug(TestCase):
|
class TestDebug(TestCase):
|
||||||
@ -50,50 +49,5 @@ class TestDebug(TestCase):
|
|||||||
'fake(23, 42)')
|
'fake(23, 42)')
|
||||||
|
|
||||||
|
|
||||||
class TestSignalCache(TestCase):
|
|
||||||
|
|
||||||
"""SignalCache tests."""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.signal1 = FakeSignal('fake1')
|
|
||||||
self.signal2 = FakeSignal('fake2')
|
|
||||||
self.cache = sigutils.SignalCache()
|
|
||||||
|
|
||||||
def test_replay(self):
|
|
||||||
"""Test simple replaying."""
|
|
||||||
self.cache.add(self.signal1, [1, 2])
|
|
||||||
self.cache.add(self.signal2, [3, 4])
|
|
||||||
self.cache.replay()
|
|
||||||
self.signal1.emit.assert_called_once_with(1, 2)
|
|
||||||
self.signal2.emit.assert_called_once_with(3, 4)
|
|
||||||
|
|
||||||
def test_update(self):
|
|
||||||
"""Test replaying when a signal was updated."""
|
|
||||||
self.cache.add(self.signal1, [1, 2])
|
|
||||||
self.cache.add(self.signal2, [3, 4])
|
|
||||||
self.cache.add(self.signal1, [5, 6])
|
|
||||||
self.cache.replay()
|
|
||||||
self.signal1.emit.assert_called_once_with(5, 6)
|
|
||||||
self.signal2.emit.assert_called_once_with(3, 4)
|
|
||||||
|
|
||||||
def test_clear(self):
|
|
||||||
"""Test clearing the signal cache."""
|
|
||||||
self.cache.add(self.signal1, [1, 2])
|
|
||||||
self.cache.add(self.signal2, [3, 4])
|
|
||||||
self.cache.clear()
|
|
||||||
self.cache.add(self.signal1, [5, 6])
|
|
||||||
self.cache.replay()
|
|
||||||
self.signal1.emit.assert_called_once_with(5, 6)
|
|
||||||
|
|
||||||
def test_uncached(self):
|
|
||||||
"""Test that uncached signals actually are uncached."""
|
|
||||||
cache = sigutils.SignalCache(uncached=['fake2'])
|
|
||||||
cache.add(self.signal1, [1, 2])
|
|
||||||
cache.add(self.signal2, [3, 4])
|
|
||||||
cache.replay()
|
|
||||||
self.signal1.emit.assert_called_once_with(1, 2)
|
|
||||||
self.assertFalse(self.signal2.emit.called)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -48,58 +48,3 @@ def dbg_signal(sig, args):
|
|||||||
A human-readable string representation of signal/args.
|
A human-readable string representation of signal/args.
|
||||||
"""
|
"""
|
||||||
return '{}({})'.format(signal_name(sig), ', '.join(map(str, args)))
|
return '{}({})'.format(signal_name(sig), ', '.join(map(str, args)))
|
||||||
|
|
||||||
|
|
||||||
class SignalCache(QObject):
|
|
||||||
|
|
||||||
"""Cache signals emitted by an object, and re-emit them later.
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
_uncached: A list of signals which should not be cached.
|
|
||||||
_signal_dict: The internal mapping of signals we got.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, uncached=None):
|
|
||||||
"""Create a new SignalCache.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
uncached: A list of signal names (as string) which should never be
|
|
||||||
cached.
|
|
||||||
"""
|
|
||||||
super().__init__()
|
|
||||||
if uncached is None:
|
|
||||||
self._uncached = []
|
|
||||||
else:
|
|
||||||
self._uncached = uncached
|
|
||||||
self._signal_dict = OrderedDict()
|
|
||||||
|
|
||||||
def add(self, sig, args):
|
|
||||||
"""Add a new signal to the signal cache.
|
|
||||||
|
|
||||||
If the signal doesn't need caching it will be ignored.
|
|
||||||
If it's already in the cache, it'll be updated and moved to the front.
|
|
||||||
If not, it will be added.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
sig: The pyqtSignal.
|
|
||||||
args: A list of arguments.
|
|
||||||
|
|
||||||
Emit:
|
|
||||||
Cached signals.
|
|
||||||
"""
|
|
||||||
if signal_name(sig) in self._uncached:
|
|
||||||
return
|
|
||||||
had_signal = sig.signal in self._signal_dict
|
|
||||||
self._signal_dict[sig.signal] = (sig, args)
|
|
||||||
if had_signal:
|
|
||||||
self._signal_dict.move_to_end(sig.signal)
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
"""Clear/purge the signal cache."""
|
|
||||||
self._signal_dict.clear()
|
|
||||||
|
|
||||||
def replay(self):
|
|
||||||
"""Replay all cached signals."""
|
|
||||||
for (signal, args) in self._signal_dict.values():
|
|
||||||
logging.debug("emitting {}".format(dbg_signal(signal, args)))
|
|
||||||
signal.emit(*args)
|
|
||||||
|
@ -44,8 +44,6 @@ class TabbedBrowser(TabWidget):
|
|||||||
in the currently visible tab.
|
in the currently visible tab.
|
||||||
|
|
||||||
For all tab-specific signals (cur_*) emitted by a tab, this happens:
|
For all tab-specific signals (cur_*) emitted by a tab, this happens:
|
||||||
- the signal gets added to a signal_cache of the tab, so it can be
|
|
||||||
emitted again if the current tab changes.
|
|
||||||
- the signal gets filtered with _filter_signals and self.cur_* gets
|
- the signal gets filtered with _filter_signals and self.cur_* gets
|
||||||
emitted if the signal occured in the current tab.
|
emitted if the signal occured in the current tab.
|
||||||
|
|
||||||
@ -62,7 +60,6 @@ class TabbedBrowser(TabWidget):
|
|||||||
cur_progress: Progress of the current tab changed (loadProgress).
|
cur_progress: Progress of the current tab changed (loadProgress).
|
||||||
cur_load_started: Current tab started loading (loadStarted)
|
cur_load_started: Current tab started loading (loadStarted)
|
||||||
cur_load_finished: Current tab finished loading (loadFinished)
|
cur_load_finished: Current tab finished loading (loadFinished)
|
||||||
cur_ssl_errors: Current tab encountered SSL errors.
|
|
||||||
cur_statusbar_message: Current tab got a statusbar message
|
cur_statusbar_message: Current tab got a statusbar message
|
||||||
(statusBarMessage)
|
(statusBarMessage)
|
||||||
cur_url_changed: Current URL changed (urlChanged)
|
cur_url_changed: Current URL changed (urlChanged)
|
||||||
@ -86,7 +83,6 @@ class TabbedBrowser(TabWidget):
|
|||||||
cur_url_changed = pyqtSignal('QUrl')
|
cur_url_changed = pyqtSignal('QUrl')
|
||||||
cur_link_hovered = pyqtSignal(str, str, str)
|
cur_link_hovered = pyqtSignal(str, str, str)
|
||||||
cur_scroll_perc_changed = pyqtSignal(int, int)
|
cur_scroll_perc_changed = pyqtSignal(int, int)
|
||||||
cur_ssl_errors = pyqtSignal('QNetworkReply*', 'QList<QSslError>')
|
|
||||||
hint_strings_updated = pyqtSignal(list)
|
hint_strings_updated = pyqtSignal(list)
|
||||||
shutdown_complete = pyqtSignal()
|
shutdown_complete = pyqtSignal()
|
||||||
quit = pyqtSignal()
|
quit = pyqtSignal()
|
||||||
@ -141,7 +137,6 @@ class TabbedBrowser(TabWidget):
|
|||||||
tab.linkHovered.connect(self._filter.create(self.cur_link_hovered))
|
tab.linkHovered.connect(self._filter.create(self.cur_link_hovered))
|
||||||
tab.loadProgress.connect(self._filter.create(self.cur_progress))
|
tab.loadProgress.connect(self._filter.create(self.cur_progress))
|
||||||
tab.loadFinished.connect(self._filter.create(self.cur_load_finished))
|
tab.loadFinished.connect(self._filter.create(self.cur_load_finished))
|
||||||
tab.ssl_errors.connect(self._filter.create(self.cur_ssl_errors))
|
|
||||||
tab.page().mainFrame().loadStarted.connect(partial(
|
tab.page().mainFrame().loadStarted.connect(partial(
|
||||||
self.on_load_started, tab))
|
self.on_load_started, tab))
|
||||||
tab.loadStarted.connect(self._filter.create(self.cur_load_started))
|
tab.loadStarted.connect(self._filter.create(self.cur_load_started))
|
||||||
@ -499,7 +494,6 @@ class TabbedBrowser(TabWidget):
|
|||||||
Args:
|
Args:
|
||||||
tab: The tab where the signal belongs to.
|
tab: The tab where the signal belongs to.
|
||||||
"""
|
"""
|
||||||
tab.signal_cache.clear()
|
|
||||||
self.setTabIcon(self.indexOf(tab), EmptyTabIcon())
|
self.setTabIcon(self.indexOf(tab), EmptyTabIcon())
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
@ -545,7 +539,6 @@ class TabbedBrowser(TabWidget):
|
|||||||
def on_current_changed(self, idx):
|
def on_current_changed(self, idx):
|
||||||
"""Set last_focused and replay signal cache if focus changed."""
|
"""Set last_focused and replay signal cache if focus changed."""
|
||||||
tab = self.widget(idx)
|
tab = self.widget(idx)
|
||||||
tab.signal_cache.replay()
|
|
||||||
self.last_focused = self.now_focused
|
self.last_focused = self.now_focused
|
||||||
self.now_focused = tab
|
self.now_focused = tab
|
||||||
|
|
||||||
|
@ -94,29 +94,17 @@ class Url(TextBase):
|
|||||||
self._urltype = val
|
self._urltype = val
|
||||||
self.setStyleSheet(get_stylesheet(self.STYLESHEET))
|
self.setStyleSheet(get_stylesheet(self.STYLESHEET))
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot(str)
|
||||||
def on_loading_started(self):
|
def on_load_status_changed(self, status):
|
||||||
"""Slot to clear SSL errors when loading started."""
|
"""Slot for load_status_changed. Sets URL color accordingly.
|
||||||
self._ssl_errors = False
|
|
||||||
|
|
||||||
@pyqtSlot('QNetworkReply*', 'QList<QSslError>')
|
|
||||||
def on_ssl_errors(self, _reply, _errors):
|
|
||||||
"""Set a flag to get a warning when there were SSL errors."""
|
|
||||||
self._ssl_errors = True
|
|
||||||
|
|
||||||
@pyqtSlot(bool)
|
|
||||||
def on_loading_finished(self, ok):
|
|
||||||
"""Slot for cur_loading_finished. Colors the URL according to ok.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ok: Whether loading finished successfully (True) or not (False).
|
status: The LoadStatus as string.
|
||||||
"""
|
"""
|
||||||
if ok and not self._ssl_errors:
|
if status in ['success', 'error', 'warn']:
|
||||||
self.urltype = 'success'
|
self.urltype = status
|
||||||
elif ok:
|
|
||||||
self.urltype = 'warn'
|
|
||||||
else:
|
else:
|
||||||
self.urltype = 'error'
|
self.urltype = 'normal'
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def set_url(self, s):
|
def set_url(self, s):
|
||||||
|
@ -32,12 +32,12 @@ import qutebrowser.utils.message as message
|
|||||||
import qutebrowser.utils.webelem as webelem
|
import qutebrowser.utils.webelem as webelem
|
||||||
from qutebrowser.browser.webpage import BrowserPage
|
from qutebrowser.browser.webpage import BrowserPage
|
||||||
from qutebrowser.browser.hints import HintManager
|
from qutebrowser.browser.hints import HintManager
|
||||||
from qutebrowser.utils.signals import SignalCache
|
|
||||||
from qutebrowser.utils.usertypes import NeighborList, enum
|
from qutebrowser.utils.usertypes import NeighborList, enum
|
||||||
from qutebrowser.commands.exceptions import CommandError
|
from qutebrowser.commands.exceptions import CommandError
|
||||||
|
|
||||||
|
|
||||||
Target = enum('normal', 'tab', 'bgtab')
|
Target = enum('normal', 'tab', 'bgtab')
|
||||||
|
LoadStatus = enum('none', 'success', 'error', 'warn', 'loading')
|
||||||
|
|
||||||
|
|
||||||
class WebView(QWebView):
|
class WebView(QWebView):
|
||||||
@ -48,11 +48,16 @@ class WebView(QWebView):
|
|||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
page_: The QWebPage behind the view
|
page_: The QWebPage behind the view
|
||||||
signal_cache: The signal cache associated with the view.
|
|
||||||
hintmanager: The HintManager instance for this view.
|
hintmanager: The HintManager instance for this view.
|
||||||
tabbedbrowser: The TabbedBrowser this WebView is part of.
|
tabbedbrowser: The TabbedBrowser this WebView is part of.
|
||||||
We need this rather than signals to make createWindow
|
We need this rather than signals to make createWindow
|
||||||
work.
|
work.
|
||||||
|
progress: loading progress of this page.
|
||||||
|
scroll_pos: The current scroll position as (x%, y%) tuple.
|
||||||
|
url: The current URL as QUrl.
|
||||||
|
_load_status: loading status of this page (index into LoadStatus)
|
||||||
|
Accessed via load_status property.
|
||||||
|
_has_ssl_errors: Whether SSL errors occured during loading.
|
||||||
_zoom: A NeighborList with the zoom levels.
|
_zoom: A NeighborList with the zoom levels.
|
||||||
_scroll_pos: The old scroll position.
|
_scroll_pos: The old scroll position.
|
||||||
_shutdown_callback: Callback to be called after shutdown.
|
_shutdown_callback: Callback to be called after shutdown.
|
||||||
@ -66,14 +71,16 @@ class WebView(QWebView):
|
|||||||
arg 1: x-position in %.
|
arg 1: x-position in %.
|
||||||
arg 2: y-position in %.
|
arg 2: y-position in %.
|
||||||
linkHovered: QWebPages linkHovered signal exposed.
|
linkHovered: QWebPages linkHovered signal exposed.
|
||||||
|
load_status_changed: The loading status changed
|
||||||
"""
|
"""
|
||||||
|
|
||||||
scroll_pos_changed = pyqtSignal(int, int)
|
scroll_pos_changed = pyqtSignal(int, int)
|
||||||
linkHovered = pyqtSignal(str, str, str)
|
linkHovered = pyqtSignal(str, str, str)
|
||||||
ssl_errors = pyqtSignal('QNetworkReply*', 'QList<QSslError>')
|
load_status_changed = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
self._load_status = LoadStatus.none
|
||||||
self.tabbedbrowser = parent
|
self.tabbedbrowser = parent
|
||||||
self._scroll_pos = (-1, -1)
|
self._scroll_pos = (-1, -1)
|
||||||
self._shutdown_callback = None
|
self._shutdown_callback = None
|
||||||
@ -82,21 +89,37 @@ class WebView(QWebView):
|
|||||||
self._destroyed = {}
|
self._destroyed = {}
|
||||||
self._zoom = None
|
self._zoom = None
|
||||||
self._init_neighborlist()
|
self._init_neighborlist()
|
||||||
|
self.progress = 0
|
||||||
|
self.loadProgress.connect(lambda p: setattr(self, 'progress', p))
|
||||||
|
self.page_.networkAccessManager().sslErrors.connect(
|
||||||
|
lambda *args: setattr(self, '_has_ssl_errors', True))
|
||||||
self.page_ = BrowserPage(self)
|
self.page_ = BrowserPage(self)
|
||||||
self.setPage(self.page_)
|
self.setPage(self.page_)
|
||||||
self.hintmanager = HintManager(self)
|
self.hintmanager = HintManager(self)
|
||||||
self.hintmanager.mouse_event.connect(self.on_mouse_event)
|
self.hintmanager.mouse_event.connect(self.on_mouse_event)
|
||||||
self.hintmanager.set_open_target.connect(self.set_force_open_target)
|
self.hintmanager.set_open_target.connect(self.set_force_open_target)
|
||||||
self.signal_cache = SignalCache(
|
|
||||||
uncached=['linkHovered', 'cur_ssl_errors'])
|
|
||||||
self.page_.setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
|
self.page_.setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
|
||||||
self.page_.linkHovered.connect(self.linkHovered)
|
self.page_.linkHovered.connect(self.linkHovered)
|
||||||
self.page_.networkAccessManager().sslErrors.connect(self.ssl_errors)
|
|
||||||
self.linkClicked.connect(self.on_link_clicked)
|
self.linkClicked.connect(self.on_link_clicked)
|
||||||
self.page_.mainFrame().loadStarted.connect(self.on_load_started)
|
self.page_.mainFrame().loadStarted.connect(self.on_load_started)
|
||||||
self.loadFinished.connect(self.on_load_finished)
|
self.loadFinished.connect(self.on_load_finished)
|
||||||
# FIXME find some way to hide scrollbars without setScrollBarPolicy
|
# FIXME find some way to hide scrollbars without setScrollBarPolicy
|
||||||
|
|
||||||
|
@property
|
||||||
|
def load_status(self):
|
||||||
|
"""Getter for load_status."""
|
||||||
|
return self._load_status
|
||||||
|
|
||||||
|
@load_status.setter
|
||||||
|
def load_status(self, val):
|
||||||
|
"""Setter for load_status.
|
||||||
|
|
||||||
|
Emit:
|
||||||
|
load_status_changed
|
||||||
|
"""
|
||||||
|
self._load_status = val
|
||||||
|
self.load_status_changed.emit(LoadStatus[val])
|
||||||
|
|
||||||
def _init_neighborlist(self):
|
def _init_neighborlist(self):
|
||||||
"""Initialize the _zoom neighborlist."""
|
"""Initialize the _zoom neighborlist."""
|
||||||
self._zoom = NeighborList(
|
self._zoom = NeighborList(
|
||||||
@ -340,13 +363,22 @@ class WebView(QWebView):
|
|||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def on_load_started(self):
|
def on_load_started(self):
|
||||||
"""Leave insert/hint mode when a new page is loading."""
|
"""Leave insert/hint mode and set vars when a new page is loading."""
|
||||||
for mode in ['insert', 'hint']:
|
for mode in ['insert', 'hint']:
|
||||||
modeman.maybe_leave(mode, 'load started')
|
modeman.maybe_leave(mode, 'load started')
|
||||||
|
self.progress = 0
|
||||||
|
self._has_ssl_errors = False
|
||||||
|
self.load_status = LoadStatus.loading
|
||||||
|
|
||||||
@pyqtSlot(bool)
|
@pyqtSlot(bool)
|
||||||
def on_load_finished(self, ok):
|
def on_load_finished(self, ok):
|
||||||
"""Handle auto-insert-mode after loading finished."""
|
"""Handle auto-insert-mode after loading finished."""
|
||||||
|
if ok and not self._has_ssl_errors:
|
||||||
|
self.urltype = 'success'
|
||||||
|
elif ok:
|
||||||
|
self.urltype = 'warn'
|
||||||
|
else:
|
||||||
|
self.urltype = 'error'
|
||||||
if not config.get('input', 'auto-insert-mode'):
|
if not config.get('input', 'auto-insert-mode'):
|
||||||
return
|
return
|
||||||
if modeman.instance().mode == 'insert' or not ok:
|
if modeman.instance().mode == 'insert' or not ok:
|
||||||
@ -424,6 +456,7 @@ class WebView(QWebView):
|
|||||||
frame.scrollBarMaximum(Qt.Vertical))
|
frame.scrollBarMaximum(Qt.Vertical))
|
||||||
perc = (round(100 * new_pos[0] / m[0]) if m[0] != 0 else 0,
|
perc = (round(100 * new_pos[0] / m[0]) if m[0] != 0 else 0,
|
||||||
round(100 * new_pos[1] / m[1]) if m[1] != 0 else 0)
|
round(100 * new_pos[1] / m[1]) if m[1] != 0 else 0)
|
||||||
|
self.scroll_pos = perc
|
||||||
self.scroll_pos_changed.emit(*perc)
|
self.scroll_pos_changed.emit(*perc)
|
||||||
# Let superclass handle the event
|
# Let superclass handle the event
|
||||||
return super().paintEvent(e)
|
return super().paintEvent(e)
|
||||||
|
Loading…
Reference in New Issue
Block a user