2019-02-05 04:59:03 +01:00
|
|
|
# Copyright: Ankitects Pty Ltd and contributors
|
2012-12-21 08:51:59 +01:00
|
|
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
2020-01-22 01:46:35 +01:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2023-01-18 12:24:16 +01:00
|
|
|
import enum
|
2023-01-09 05:39:31 +01:00
|
|
|
import re
|
2023-01-18 12:24:16 +01:00
|
|
|
from typing import Any, Callable, Optional, cast
|
2020-02-15 23:22:41 +01:00
|
|
|
|
2020-01-22 01:46:35 +01:00
|
|
|
import aqt
|
2021-01-31 06:55:08 +01:00
|
|
|
from anki.sync import SyncStatus
|
2023-01-18 12:24:16 +01:00
|
|
|
from aqt import gui_hooks, props
|
2019-12-20 10:19:03 +01:00
|
|
|
from aqt.qt import *
|
2020-06-02 05:23:01 +02:00
|
|
|
from aqt.sync import get_sync_status
|
2023-01-18 12:24:16 +01:00
|
|
|
from aqt.theme import theme_manager
|
2021-03-26 05:21:04 +01:00
|
|
|
from aqt.utils import tr
|
2023-02-10 05:53:11 +01:00
|
|
|
from aqt.webview import AnkiWebView, AnkiWebViewKind
|
2019-12-20 10:19:03 +01:00
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2023-01-18 12:24:16 +01:00
|
|
|
class HideMode(enum.IntEnum):
|
|
|
|
FULLSCREEN = 0
|
|
|
|
ALWAYS = 1
|
|
|
|
|
|
|
|
|
2020-02-08 23:59:29 +01:00
|
|
|
# wrapper class for set_bridge_command()
|
|
|
|
class TopToolbar:
|
2020-02-27 03:10:38 +01:00
|
|
|
def __init__(self, toolbar: Toolbar) -> None:
|
2020-02-08 23:59:29 +01:00
|
|
|
self.toolbar = toolbar
|
|
|
|
|
|
|
|
|
|
|
|
# wrapper class for set_bridge_command()
|
|
|
|
class BottomToolbar:
|
2020-02-27 03:10:38 +01:00
|
|
|
def __init__(self, toolbar: Toolbar) -> None:
|
2020-02-08 23:59:29 +01:00
|
|
|
self.toolbar = toolbar
|
|
|
|
|
|
|
|
|
2023-01-09 05:39:31 +01:00
|
|
|
class ToolbarWebView(AnkiWebView):
|
2023-01-18 12:24:16 +01:00
|
|
|
hide_condition: Callable[..., bool]
|
|
|
|
|
2023-02-10 05:53:11 +01:00
|
|
|
def __init__(self, mw: aqt.AnkiQt, kind: AnkiWebViewKind | None = None) -> None:
|
|
|
|
AnkiWebView.__init__(self, mw, kind=kind)
|
2023-01-09 05:39:31 +01:00
|
|
|
self.mw = mw
|
|
|
|
self.setFocusPolicy(Qt.FocusPolicy.WheelFocus)
|
|
|
|
self.disable_zoom()
|
2023-01-18 12:24:16 +01:00
|
|
|
self.hidden = False
|
2023-01-09 05:39:31 +01:00
|
|
|
self.hide_timer = QTimer()
|
|
|
|
self.hide_timer.setSingleShot(True)
|
2023-01-18 12:24:16 +01:00
|
|
|
self.reset_timer()
|
|
|
|
|
|
|
|
def reset_timer(self) -> None:
|
|
|
|
self.hide_timer.stop()
|
|
|
|
self.hide_timer.setInterval(2000)
|
|
|
|
|
|
|
|
def hide(self) -> None:
|
|
|
|
self.hidden = True
|
|
|
|
|
|
|
|
def show(self) -> None:
|
|
|
|
self.hidden = False
|
|
|
|
|
|
|
|
|
|
|
|
class TopWebView(ToolbarWebView):
|
2023-02-10 05:53:11 +01:00
|
|
|
def __init__(self, mw: aqt.AnkiQt) -> None:
|
|
|
|
super().__init__(mw, kind=AnkiWebViewKind.TOP_TOOLBAR)
|
2023-01-18 12:24:16 +01:00
|
|
|
self.web_height = 0
|
|
|
|
qconnect(self.hide_timer.timeout, self.hide_if_allowed)
|
2023-01-09 05:39:31 +01:00
|
|
|
|
|
|
|
def eventFilter(self, obj, evt):
|
|
|
|
if handled := super().eventFilter(obj, evt):
|
|
|
|
return handled
|
|
|
|
|
2023-01-18 12:24:16 +01:00
|
|
|
# prevent collapse of both toolbars if pointer is inside one of them
|
2023-01-09 05:39:31 +01:00
|
|
|
if evt.type() == QEvent.Type.Enter:
|
2023-01-18 12:24:16 +01:00
|
|
|
self.reset_timer()
|
|
|
|
self.mw.bottomWeb.reset_timer()
|
2023-01-09 05:39:31 +01:00
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
2023-01-18 12:24:16 +01:00
|
|
|
def on_body_classes_need_update(self) -> None:
|
|
|
|
super().on_body_classes_need_update()
|
|
|
|
|
|
|
|
if self.mw.state == "review":
|
|
|
|
if self.mw.pm.hide_top_bar():
|
|
|
|
self.eval("""document.body.classList.remove("flat"); """)
|
|
|
|
else:
|
|
|
|
self.flatten()
|
|
|
|
|
|
|
|
self.show()
|
|
|
|
|
2023-01-09 05:39:31 +01:00
|
|
|
def _onHeight(self, qvar: Optional[int]) -> None:
|
|
|
|
super()._onHeight(qvar)
|
|
|
|
self.web_height = int(qvar)
|
|
|
|
|
2023-01-18 12:24:16 +01:00
|
|
|
def hide_if_allowed(self) -> None:
|
|
|
|
if self.mw.state != "review":
|
|
|
|
return
|
|
|
|
|
|
|
|
if self.mw.pm.hide_top_bar():
|
|
|
|
if (
|
|
|
|
self.mw.pm.top_bar_hide_mode() == HideMode.FULLSCREEN
|
|
|
|
and not self.mw.windowState() & Qt.WindowState.WindowFullScreen
|
|
|
|
):
|
|
|
|
self.show()
|
|
|
|
return
|
2023-01-09 05:39:31 +01:00
|
|
|
|
2023-01-18 12:24:16 +01:00
|
|
|
self.hide()
|
|
|
|
|
|
|
|
def hide(self) -> None:
|
|
|
|
super().hide()
|
|
|
|
|
|
|
|
self.hidden = True
|
|
|
|
self.eval(
|
|
|
|
"""document.body.classList.add("hidden"); """,
|
|
|
|
)
|
|
|
|
if self.mw.fullscreen:
|
|
|
|
self.mw.hide_menubar()
|
|
|
|
|
|
|
|
def show(self) -> None:
|
|
|
|
super().show()
|
|
|
|
|
|
|
|
self.eval("""document.body.classList.remove("hidden"); """)
|
|
|
|
self.mw.show_menubar()
|
2023-01-09 05:39:31 +01:00
|
|
|
|
|
|
|
def flatten(self) -> None:
|
2023-01-18 12:24:16 +01:00
|
|
|
self.eval("""document.body.classList.add("flat"); """)
|
2023-01-09 05:39:31 +01:00
|
|
|
|
|
|
|
def elevate(self) -> None:
|
|
|
|
self.eval(
|
|
|
|
"""
|
|
|
|
document.body.classList.remove("flat");
|
|
|
|
document.body.style.removeProperty("background");
|
|
|
|
"""
|
|
|
|
)
|
|
|
|
|
|
|
|
def update_background_image(self) -> None:
|
2023-01-18 12:24:16 +01:00
|
|
|
if self.mw.pm.minimalist_mode():
|
|
|
|
return
|
|
|
|
|
|
|
|
def set_background(computed: str) -> None:
|
2023-01-09 05:39:31 +01:00
|
|
|
# remove offset from copy
|
2023-01-18 12:24:16 +01:00
|
|
|
background = re.sub(r"-\d+px ", "0%", computed)
|
|
|
|
# ensure alignment with main webview
|
|
|
|
background = re.sub(r"\sfixed", "", background)
|
2023-01-09 05:39:31 +01:00
|
|
|
# change computedStyle px value back to 100vw
|
|
|
|
background = re.sub(r"\d+px", "100vw", background)
|
|
|
|
|
|
|
|
self.eval(
|
2023-01-18 12:24:16 +01:00
|
|
|
f"""
|
|
|
|
document.body.style.setProperty("background", '{background}');
|
|
|
|
"""
|
2023-01-09 05:39:31 +01:00
|
|
|
)
|
2023-01-18 12:24:16 +01:00
|
|
|
self.set_body_height(self.mw.web.height())
|
|
|
|
|
2023-01-09 05:39:31 +01:00
|
|
|
# offset reviewer background by toolbar height
|
|
|
|
self.mw.web.eval(
|
|
|
|
f"""document.body.style.setProperty("background-position-y", "-{self.web_height}px"); """
|
|
|
|
)
|
|
|
|
|
|
|
|
self.mw.web.evalWithCallback(
|
|
|
|
"""window.getComputedStyle(document.body).background; """,
|
|
|
|
set_background,
|
|
|
|
)
|
|
|
|
|
2023-01-18 12:24:16 +01:00
|
|
|
def set_body_height(self, height: int) -> None:
|
|
|
|
self.eval(
|
|
|
|
f"""document.body.style.setProperty("min-height", "{self.mw.web.height()}px"); """
|
|
|
|
)
|
|
|
|
|
|
|
|
def adjustHeightToFit(self) -> None:
|
|
|
|
self.eval("""document.body.style.setProperty("min-height", "0px"); """)
|
|
|
|
self.evalWithCallback("document.documentElement.offsetHeight", self._onHeight)
|
|
|
|
|
|
|
|
def resizeEvent(self, event: QResizeEvent) -> None:
|
|
|
|
super().resizeEvent(event)
|
|
|
|
|
|
|
|
self.mw.web.evalWithCallback(
|
|
|
|
"""window.innerHeight; """,
|
|
|
|
self.set_body_height,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class BottomWebView(ToolbarWebView):
|
2023-02-10 05:53:11 +01:00
|
|
|
def __init__(self, mw: aqt.AnkiQt) -> None:
|
|
|
|
super().__init__(mw, kind=AnkiWebViewKind.BOTTOM_TOOLBAR)
|
2023-01-18 12:24:16 +01:00
|
|
|
qconnect(self.hide_timer.timeout, self.hide_if_allowed)
|
|
|
|
|
|
|
|
def eventFilter(self, obj, evt):
|
|
|
|
if handled := super().eventFilter(obj, evt):
|
|
|
|
return handled
|
|
|
|
|
|
|
|
if evt.type() == QEvent.Type.Enter:
|
|
|
|
self.reset_timer()
|
|
|
|
self.mw.toolbarWeb.reset_timer()
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
def on_body_classes_need_update(self) -> None:
|
|
|
|
super().on_body_classes_need_update()
|
|
|
|
if self.mw.state == "review":
|
|
|
|
self.show()
|
|
|
|
|
|
|
|
def animate_height(self, height: int) -> None:
|
|
|
|
self.web_height = height
|
|
|
|
|
|
|
|
if self.mw.pm.reduce_motion():
|
|
|
|
self.setFixedHeight(height)
|
|
|
|
else:
|
|
|
|
# Collapse/Expand animation
|
|
|
|
self.setMinimumHeight(0)
|
|
|
|
self.animation = QPropertyAnimation(
|
|
|
|
self, cast(QByteArray, b"maximumHeight")
|
|
|
|
)
|
|
|
|
self.animation.setDuration(int(theme_manager.var(props.TRANSITION)))
|
|
|
|
self.animation.setStartValue(self.height())
|
|
|
|
self.animation.setEndValue(height)
|
|
|
|
qconnect(self.animation.finished, lambda: self.setFixedHeight(height))
|
|
|
|
self.animation.start()
|
|
|
|
|
|
|
|
def hide_if_allowed(self) -> None:
|
|
|
|
if self.mw.state != "review":
|
|
|
|
return
|
|
|
|
|
|
|
|
if self.mw.pm.hide_bottom_bar():
|
|
|
|
if (
|
|
|
|
self.mw.pm.bottom_bar_hide_mode() == HideMode.FULLSCREEN
|
|
|
|
and not self.mw.windowState() & Qt.WindowState.WindowFullScreen
|
|
|
|
):
|
|
|
|
self.show()
|
|
|
|
return
|
|
|
|
|
|
|
|
self.hide()
|
|
|
|
|
|
|
|
def hide(self) -> None:
|
|
|
|
super().hide()
|
|
|
|
|
|
|
|
self.hidden = True
|
|
|
|
self.animate_height(1)
|
|
|
|
|
|
|
|
def show(self) -> None:
|
|
|
|
super().show()
|
|
|
|
|
|
|
|
self.hidden = False
|
|
|
|
if self.mw.state == "review":
|
|
|
|
self.evalWithCallback(
|
|
|
|
"document.documentElement.offsetHeight", self.animate_height
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
self.adjustHeightToFit()
|
|
|
|
|
2023-01-09 05:39:31 +01:00
|
|
|
|
2017-02-06 23:21:33 +01:00
|
|
|
class Toolbar:
|
2020-01-22 01:46:35 +01:00
|
|
|
def __init__(self, mw: aqt.AnkiQt, web: AnkiWebView) -> None:
|
2012-12-21 08:51:59 +01:00
|
|
|
self.mw = mw
|
|
|
|
self.web = web
|
2021-10-03 10:59:42 +02:00
|
|
|
self.link_handlers: dict[str, Callable] = {
|
2012-12-21 08:51:59 +01:00
|
|
|
"study": self._studyLinkHandler,
|
|
|
|
}
|
2018-10-12 04:08:19 +02:00
|
|
|
self.web.requiresCol = False
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2020-02-12 22:00:13 +01:00
|
|
|
def draw(
|
|
|
|
self,
|
|
|
|
buf: str = "",
|
2021-10-03 10:59:42 +02:00
|
|
|
web_context: Any | None = None,
|
|
|
|
link_handler: Callable[[str], Any] | None = None,
|
2020-02-27 03:10:38 +01:00
|
|
|
) -> None:
|
2020-02-12 22:00:13 +01:00
|
|
|
web_context = web_context or TopToolbar(self)
|
|
|
|
link_handler = link_handler or self._linkHandler
|
|
|
|
self.web.set_bridge_command(link_handler, web_context)
|
2023-01-09 23:48:50 +01:00
|
|
|
body = self._body.format(
|
|
|
|
toolbar_content=self._centerLinks(),
|
|
|
|
left_tray_content=self._left_tray_content(),
|
|
|
|
right_tray_content=self._right_tray_content(),
|
|
|
|
)
|
2020-02-12 22:00:13 +01:00
|
|
|
self.web.stdHtml(
|
2023-01-09 23:48:50 +01:00
|
|
|
body,
|
2020-11-01 05:26:58 +01:00
|
|
|
css=["css/toolbar.css"],
|
2022-06-10 15:33:53 +02:00
|
|
|
js=["js/vendor/jquery.min.js", "js/toolbar.js"],
|
2020-06-02 05:23:01 +02:00
|
|
|
context=web_context,
|
2020-02-12 22:00:13 +01:00
|
|
|
)
|
2017-08-02 08:22:54 +02:00
|
|
|
self.web.adjustHeightToFit()
|
2020-06-02 05:23:01 +02:00
|
|
|
|
|
|
|
def redraw(self) -> None:
|
|
|
|
self.set_sync_active(self.mw.media_syncer.is_syncing())
|
|
|
|
self.update_sync_status()
|
2020-07-10 17:38:40 +02:00
|
|
|
gui_hooks.top_toolbar_did_redraw(self)
|
2012-12-21 08:51:59 +01:00
|
|
|
|
|
|
|
# Available links
|
|
|
|
######################################################################
|
|
|
|
|
2020-02-20 18:22:31 +01:00
|
|
|
def create_link(
|
|
|
|
self,
|
|
|
|
cmd: str,
|
|
|
|
label: str,
|
|
|
|
func: Callable,
|
2021-10-03 10:59:42 +02:00
|
|
|
tip: str | None = None,
|
|
|
|
id: str | None = None,
|
2020-02-20 18:22:31 +01:00
|
|
|
) -> str:
|
|
|
|
"""Generates HTML link element and registers link handler
|
2020-08-31 05:29:28 +02:00
|
|
|
|
2020-02-20 18:22:31 +01:00
|
|
|
Arguments:
|
|
|
|
cmd {str} -- Command name used for the JS → Python bridge
|
|
|
|
label {str} -- Display label of the link
|
|
|
|
func {Callable} -- Callable to be called on clicking the link
|
2020-08-31 05:29:28 +02:00
|
|
|
|
2020-02-20 18:22:31 +01:00
|
|
|
Keyword Arguments:
|
|
|
|
tip {Optional[str]} -- Optional tooltip text to show on hovering
|
|
|
|
over the link (default: {None})
|
|
|
|
id: {Optional[str]} -- Optional id attribute to supply the link with
|
|
|
|
(default: {None})
|
2020-08-31 05:29:28 +02:00
|
|
|
|
2020-02-20 18:22:31 +01:00
|
|
|
Returns:
|
|
|
|
str -- HTML link element
|
|
|
|
"""
|
|
|
|
|
|
|
|
self.link_handlers[cmd] = func
|
|
|
|
|
|
|
|
title_attr = f'title="{tip}"' if tip else ""
|
|
|
|
id_attr = f'id="{id}"' if id else ""
|
2020-02-20 16:15:50 +01:00
|
|
|
|
|
|
|
return (
|
2020-02-20 18:22:31 +01:00
|
|
|
f"""<a class=hitem tabindex="-1" aria-label="{label}" """
|
|
|
|
f"""{title_attr} {id_attr} href=# onclick="return pycmd('{cmd}')">"""
|
|
|
|
f"""{label}</a>"""
|
2020-02-20 16:15:50 +01:00
|
|
|
)
|
2020-02-15 23:22:41 +01:00
|
|
|
|
2020-02-27 03:10:38 +01:00
|
|
|
def _centerLinks(self) -> str:
|
2012-12-21 08:51:59 +01:00
|
|
|
links = [
|
2020-02-20 18:22:31 +01:00
|
|
|
self.create_link(
|
|
|
|
"decks",
|
2021-03-26 04:48:26 +01:00
|
|
|
tr.actions_decks(),
|
2020-02-20 18:22:31 +01:00
|
|
|
self._deckLinkHandler,
|
2021-03-26 05:21:04 +01:00
|
|
|
tip=tr.actions_shortcut_key(val="D"),
|
2020-02-20 18:22:31 +01:00
|
|
|
id="decks",
|
|
|
|
),
|
|
|
|
self.create_link(
|
|
|
|
"add",
|
2021-03-26 04:48:26 +01:00
|
|
|
tr.actions_add(),
|
2020-02-20 18:22:31 +01:00
|
|
|
self._addLinkHandler,
|
2021-03-26 05:21:04 +01:00
|
|
|
tip=tr.actions_shortcut_key(val="A"),
|
2020-02-20 18:22:31 +01:00
|
|
|
id="add",
|
|
|
|
),
|
|
|
|
self.create_link(
|
|
|
|
"browse",
|
2021-03-26 04:48:26 +01:00
|
|
|
tr.qt_misc_browse(),
|
2020-02-20 18:22:31 +01:00
|
|
|
self._browseLinkHandler,
|
2021-03-26 05:21:04 +01:00
|
|
|
tip=tr.actions_shortcut_key(val="B"),
|
2020-02-20 18:22:31 +01:00
|
|
|
id="browse",
|
|
|
|
),
|
|
|
|
self.create_link(
|
|
|
|
"stats",
|
2021-03-26 04:48:26 +01:00
|
|
|
tr.qt_misc_stats(),
|
2020-02-20 18:22:31 +01:00
|
|
|
self._statsLinkHandler,
|
2021-03-26 05:21:04 +01:00
|
|
|
tip=tr.actions_shortcut_key(val="T"),
|
2020-02-20 18:22:31 +01:00
|
|
|
id="stats",
|
|
|
|
),
|
2012-12-21 08:51:59 +01:00
|
|
|
]
|
2020-02-20 16:15:50 +01:00
|
|
|
|
|
|
|
links.append(self._create_sync_link())
|
|
|
|
|
2020-02-20 16:23:33 +01:00
|
|
|
gui_hooks.top_toolbar_did_init_links(links, self)
|
2020-02-20 16:15:50 +01:00
|
|
|
|
|
|
|
return "\n".join(links)
|
|
|
|
|
2023-01-09 23:48:50 +01:00
|
|
|
# Add-ons
|
|
|
|
######################################################################
|
|
|
|
|
|
|
|
def _left_tray_content(self) -> str:
|
|
|
|
left_tray_content: list[str] = []
|
|
|
|
gui_hooks.top_toolbar_will_set_left_tray_content(left_tray_content, self)
|
|
|
|
return self._process_tray_content(left_tray_content)
|
|
|
|
|
|
|
|
def _right_tray_content(self) -> str:
|
|
|
|
right_tray_content: list[str] = []
|
|
|
|
gui_hooks.top_toolbar_will_set_right_tray_content(right_tray_content, self)
|
|
|
|
return self._process_tray_content(right_tray_content)
|
|
|
|
|
|
|
|
def _process_tray_content(self, content: list[str]) -> str:
|
|
|
|
return "\n".join(f"""<div class="tray-item">{item}</div>""" for item in content)
|
|
|
|
|
2020-06-02 05:23:01 +02:00
|
|
|
# Sync
|
|
|
|
######################################################################
|
|
|
|
|
2020-02-20 16:15:50 +01:00
|
|
|
def _create_sync_link(self) -> str:
|
2021-03-26 04:48:26 +01:00
|
|
|
name = tr.qt_misc_sync()
|
2021-03-26 05:21:04 +01:00
|
|
|
title = tr.actions_shortcut_key(val="Y")
|
2020-02-04 02:41:20 +01:00
|
|
|
label = "sync"
|
2020-02-20 16:15:50 +01:00
|
|
|
self.link_handlers[label] = self._syncLinkHandler
|
|
|
|
|
2020-02-04 02:41:20 +01:00
|
|
|
return f"""
|
2022-08-22 03:26:57 +02:00
|
|
|
<a class=hitem tabindex="-1" aria-label="{name}" title="{title}" id="{label}" href=# onclick="return pycmd('{label}')"
|
|
|
|
>{name}<img id=sync-spinner src='/_anki/imgs/refresh.svg'>
|
2020-02-04 02:41:20 +01:00
|
|
|
</a>"""
|
|
|
|
|
|
|
|
def set_sync_active(self, active: bool) -> None:
|
2021-04-13 19:59:00 +02:00
|
|
|
method = "add" if active else "remove"
|
2021-04-13 20:29:59 +02:00
|
|
|
self.web.eval(
|
|
|
|
f"document.getElementById('sync-spinner').classList.{method}('spin')"
|
|
|
|
)
|
2020-02-04 02:41:20 +01:00
|
|
|
|
2020-06-02 05:23:01 +02:00
|
|
|
def set_sync_status(self, status: SyncStatus) -> None:
|
|
|
|
self.web.eval(f"updateSyncColor({status.required})")
|
|
|
|
|
|
|
|
def update_sync_status(self) -> None:
|
|
|
|
get_sync_status(self.mw, self.mw.toolbar.set_sync_status)
|
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
# Link handling
|
|
|
|
######################################################################
|
|
|
|
|
2020-02-27 03:10:38 +01:00
|
|
|
def _linkHandler(self, link: str) -> bool:
|
2012-12-21 08:51:59 +01:00
|
|
|
if link in self.link_handlers:
|
2016-05-31 10:51:40 +02:00
|
|
|
self.link_handlers[link]()
|
|
|
|
return False
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2020-02-27 03:10:38 +01:00
|
|
|
def _deckLinkHandler(self) -> None:
|
2012-12-23 04:28:06 +01:00
|
|
|
self.mw.moveToState("deckBrowser")
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2020-02-27 03:10:38 +01:00
|
|
|
def _studyLinkHandler(self) -> None:
|
2012-12-23 04:28:06 +01:00
|
|
|
# if overview already shown, switch to review
|
|
|
|
if self.mw.state == "overview":
|
|
|
|
self.mw.col.startTimebox()
|
|
|
|
self.mw.moveToState("review")
|
|
|
|
else:
|
2019-03-04 07:54:22 +01:00
|
|
|
self.mw.onOverview()
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2020-02-27 03:10:38 +01:00
|
|
|
def _addLinkHandler(self) -> None:
|
2012-12-23 04:28:06 +01:00
|
|
|
self.mw.onAddCard()
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2020-02-27 03:10:38 +01:00
|
|
|
def _browseLinkHandler(self) -> None:
|
2012-12-23 04:28:06 +01:00
|
|
|
self.mw.onBrowse()
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2020-02-27 03:10:38 +01:00
|
|
|
def _statsLinkHandler(self) -> None:
|
2012-12-23 04:28:06 +01:00
|
|
|
self.mw.onStats()
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2020-02-27 03:10:38 +01:00
|
|
|
def _syncLinkHandler(self) -> None:
|
2020-05-31 02:53:54 +02:00
|
|
|
self.mw.on_sync_button_clicked()
|
2012-12-21 08:51:59 +01:00
|
|
|
|
|
|
|
# HTML & CSS
|
|
|
|
######################################################################
|
|
|
|
|
|
|
|
_body = """
|
2023-01-09 23:48:50 +01:00
|
|
|
<div class="header">
|
|
|
|
<div class="left-tray">{left_tray_content}</div>
|
|
|
|
<div class="toolbar">{toolbar_content}</div>
|
|
|
|
<div class="right-tray">{right_tray_content}</div>
|
2023-01-09 05:39:31 +01:00
|
|
|
</div>
|
2012-12-21 08:51:59 +01:00
|
|
|
"""
|
|
|
|
|
2019-12-23 01:34:10 +01:00
|
|
|
|
2017-08-02 08:22:54 +02:00
|
|
|
# Bottom bar
|
|
|
|
######################################################################
|
|
|
|
|
2019-12-23 01:34:10 +01:00
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
class BottomBar(Toolbar):
|
|
|
|
|
|
|
|
_centerBody = """
|
2016-06-07 06:27:33 +02:00
|
|
|
<center id=outer><table width=100%% id=header><tr><td align=center>
|
2012-12-21 08:51:59 +01:00
|
|
|
%s</td></tr></table></center>
|
|
|
|
"""
|
|
|
|
|
2020-02-12 22:00:13 +01:00
|
|
|
def draw(
|
|
|
|
self,
|
|
|
|
buf: str = "",
|
2021-10-03 10:59:42 +02:00
|
|
|
web_context: Any | None = None,
|
|
|
|
link_handler: Callable[[str], Any] | None = None,
|
2020-02-27 03:10:38 +01:00
|
|
|
) -> None:
|
2020-01-22 01:46:35 +01:00
|
|
|
# note: some screens may override this
|
2020-02-12 22:00:13 +01:00
|
|
|
web_context = web_context or BottomToolbar(self)
|
|
|
|
link_handler = link_handler or self._linkHandler
|
|
|
|
self.web.set_bridge_command(link_handler, web_context)
|
2012-12-21 08:51:59 +01:00
|
|
|
self.web.stdHtml(
|
2020-02-12 22:00:13 +01:00
|
|
|
self._centerBody % buf,
|
2020-11-01 05:26:58 +01:00
|
|
|
css=["css/toolbar.css", "css/toolbar-bottom.css"],
|
2020-02-12 22:00:13 +01:00
|
|
|
context=web_context,
|
2019-12-23 01:34:10 +01:00
|
|
|
)
|
2017-08-02 08:22:54 +02:00
|
|
|
self.web.adjustHeightToFit()
|