def __init__(self): AnkiQt.moveToState = wrap(AnkiQt.moveToState, AnkiQt_moveToState(self), "before") Deck.answerCard = wrap(Deck.answerCard, Deck_answerCard(self), "after") self.config = config.Config(mw.config) self.api = AnnikkiClient(self, self.config) self.setup_ui() self.cards_answered = []
def __init__(self): # Setup self.db = DBConnect() self.__treasureChest = TreasureChest(self.db) self.__options = Options(self.db) self.__eventManager = EventManager(self, self.__options, self.__treasureChest) self.__stats = Stats(self.db, self.__eventManager) world = World(self.db, self.__options.getOption('activeCountry')) self.__buildingAuthority = BuildingAuthority(self, world) self.__ranks = Ranks(self.db, self.__eventManager, world) self.__ranks.updateRank(self.__treasureChest.getTotalGold(), self.__buildingAuthority.getActiveCountry().getCompletedObjectsPercentage(), True) self.__layout = None # Setup as a property as we must be able to clear it self.__view = None # Keep's track of current view. Useful if we want to update a view, but we're not sure which one self.deckSelected = False # Setup window QDialog.__init__(self, mw, Qt.WindowTitleHint) self.setWindowTitle(getPluginName()) self.resize(300, 800) self.command("MainView||main") # Wrap Anki methods Reviewer._answerCard = wrap(self.answerCard, Reviewer._answerCard) _Collection.undo = wrap(_Collection.undo, self.undo) DeckManager.select = wrap(DeckManager.select, self.refreshSettings) # Add AnkiEmperor to the Anki menu action = QAction(getPluginName(), mw) mw.connect(action, SIGNAL("triggered()"), self.show) mw.form.menuTools.addAction(action)
def setupFunctions(self, imageResizer): """Replace functions in anki """ # setup button Editor.setupButtons = wrap(Editor.setupButtons, ImageResizerButton, 'after') Editor.imageResizer = imageResizer EditorWebView._processMime = wrap(EditorWebView._processMime, _processMime_around, 'around')
def profileLoaded(): # add menu entry mw.addonManager.rebuildAddonsMenu = wrap(mw.addonManager.rebuildAddonsMenu, siblingMenu) mw.addonManager.rebuildAddonsMenu() # add scheduler anki.sched.Scheduler._adjRevIvl = wrap(anki.sched.Scheduler._adjRevIvl, siblingIvl, "around")
def anknotes_onload(): # write_file_contents('%s: anknotes_onload' % __name__, 'load') if in_anki(): addHook("profileLoaded", anknotes_profile_loaded) if ANKNOTES.HOOKS.DB: DB.scalar = anknotes_scalar # wrap(DB.scalar, anknotes_scalar, "before") DB.execute = wrap(DB.execute, anknotes_execute, "before") if ANKNOTES.HOOKS.SEARCH: addHook("search", anknotes_search_hook) Finder._query = wrap(Finder._query, anknotes_finder_query_wrap, "around") Finder.findCards = wrap(Finder.findCards, anknotes_finder_findCards_wrap, "around") browser.Browser._systemTagTree = wrap(browser.Browser._systemTagTree, anknotes_browser_tagtree_wrap, "around") # write_file_contents('%s: anknotes_onload: anknotes_setup_menu' % __name__, 'load') menu.anknotes_setup_menu() Preferences.setupOptions = wrap(Preferences.setupOptions, settings.setup_evernote)
def setupHanziGraph(self, graphwindow): log.info("Beginning setup of Hanzi graph on the graph window") # Don't add a graph if the deck doesn't have a Mandarin tag. This might be too conservative (the user # could add a Mandarin tag and then refresh) but in general it's going to work well to hide it from the # user on their non-Mandarin decks. if len(self.suitableModelIds()) == 0: return # NB: we used to preload the Hanzi data at this point, but that makes the ``refresh'' button not work, # because we have no means of clearing the preloaded data, so now it lives on the class. We also used to # avoid adding the graph if the current deck was not # Append our own graph at the end from ankiqt.ui.graphs import AdjustableFigure extragraph = AdjustableFigure(graphwindow.parent, 'hanzi', lambda days: self.calculateHanziData(graphwindow, days), graphwindow.range) extragraph.addWidget(QtGui.QLabel("<h1>Unique Hanzi (Cumulative, By HSK Level)</h1>")) graphwindow.vbox.addWidget(extragraph) graphwindow.widgets.append(extragraph) # Add our graph to the name map - this is necessary to avoid exceptions when using show/hide graphwindow.nameMap['hanzi'] = "Unique Hanzi (Cumulative, By HSK Level)" # To allow refreshing to work properly, we have to intercept the call to updateFigure() made by Ankis onRefresh code extragraph.updateFigure = wrap(extragraph.updateFigure, self.invalidateHanziData, "before")
def initPlugin(): main.AnkiQt.showAnswerButton = wrap(main.AnkiQt.showAnswerButton, afterShowAnswerButton, "after") main.AnkiQt.keyPressEvent = wrap(main.AnkiQt.keyPressEvent, aroundKeyPressEvent, "around") view.View.drawAnswer = wrap(view.View.drawAnswer, aroundDrawAnswer, "around") menu = QAction(mw) menu.setText("Add Password") mw.connect(menu, SIGNAL("triggered()"), addPassword) menu2 = QAction(mw) menu2.setText("Set GPG User Name") mw.connect(menu2, SIGNAL("triggered()"), setGPGName) mw.mainWin.menuTools.addSeparator() mw.mainWin.menuTools.addAction(menu) mw.mainWin.menuTools.addAction(menu2) config.load() if not config.loaded: setGPGName()
def install(self): from anki.hooks import wrap import ankiqt.ui.facteditor log.info("Installing color shortcut keys hook") ankiqt.ui.facteditor.FactEditor.setupFields = wrap(ankiqt.ui.facteditor.FactEditor.setupFields, self.setupShortcuts, "after") self.setupShortcuts(self.mw.editor)
def profileLoaded(): """Support for Advanced Previewer""" try: from advanced_previewer.previewer import Previewer except ImportError: return Previewer.linkHandler = wrap( Previewer.linkHandler, linkHandler, "around") addHook("previewerMungeQA", linkInserter)
def profileLoaded(): '''Initialize Kanji Info''' # load the kanji_info.txt init_kanji_info() # add menu entry mw.addonManager.rebuildAddonsMenu = wrap(mw.addonManager.rebuildAddonsMenu, kanji_info_Menu) mw.addonManager.rebuildAddonsMenu()
def __init__(cls, name, bases, attributes): super().__init__(name, bases, attributes) # singleton cls.instance = None old_creator = cls.__new__ cls.__new__ = singleton_creator(old_creator) # additions and replacements cls.additions = {} cls.replacements = {} target = attributes.get('target', None) def callback_maker(wrapper): def raw_new(*args, **kwargs): return wrapper(cls.instance, *args, **kwargs) return raw_new for key, attr in attributes.items(): if key == 'init': key = '__init__' if hasattr(attr, 'wraps'): if not target: raise Exception(f'Asked to wrap "{key}" but target of {name} not defined') original = getattr(target, key) if type(original) is MethodType: original = original.__func__ new = wrap(original, callback_maker(attr), attr.position) # for classes, just add the new function, it will be bound later, # but instances need some more work: we need to bind! if not isclass(target): new = MethodType(new, target) cls.replacements[key] = new if hasattr(attr, 'appends_in_night_mode'): if not target: raise Exception(f'Asked to replace "{key}" but target of {name} not defined') cls.additions[key] = attr if hasattr(attr, 'replaces_in_night_mode'): if not target: raise Exception(f'Asked to replace "{key}" but target of {name} not defined') cls.replacements[key] = attr # TODO: invoke and cache css? if hasattr(attr, 'is_css'): pass
def install(self): log.info("Installing Hanzi graph hook") # NB: must lazy-load ankiqt.ui.graphs because importing it will fail if the user doesn't # have python-matplotlib installed on Linux. try: from ankiqt.ui.graphs import GraphWindow GraphWindow.setupGraphs = wrap(GraphWindow.setupGraphs, self.setupHanziGraph, "after") except ImportError, e: self.notifier.exception("There was a problem setting up the Hanzi Graph! If you are using Linux, " + "you may need to install the package providing matplotlib to Python. On Ubuntu " + "you can do that by running 'sudo apt-get install python-matplotlib' in the Terminal.")
def main(): # Query system colours. p = QPalette() textcolour = p.color(QPalette.Text) basecolour = p.color(QPalette.Base) # Inject background colour into the browser. def tree_colour_hook(self): p = self.form.tree.palette() p.setColor(QPalette.Base, basecolour) self.form.tree.setPalette(p) browser.Browser.setupTree = wrap(browser.Browser.setupTree, tree_colour_hook) # Change suspend and mark colours. coloursuspended = QColor() coloursuspended.setNamedColor(browser.COLOUR_SUSPENDED) colourmarked = QColor() colourmarked.setNamedColor(browser.COLOUR_MARKED) lightness_blacklist = [textcolour.lightness()] hue_blacklist = [basecolour.hue(), textcolour.hue()] lightness_preference = max(basecolour.lightness(), 40) for colour in [coloursuspended, colourmarked]: (h, s, l, a) = colour.getHsl() new_lightness = get_new_lightness(lightness_blacklist, lightness_preference) # print("Considering {0} with preference {2} choose lightness {1}\n".format( # lightness_blacklist, new_lightness, lightness_preference)) new_hue = get_new_hue(hue_blacklist, h) # print("Considering {0} with preference {2} choose hue {1}\n".format( # hue_blacklist, new_hue, h)) hue_blacklist.append(new_hue) colour.setHsl(new_hue, s, new_lightness, a) browser.COLOUR_SUSPENDED = coloursuspended.name() browser.COLOUR_MARKED = colourmarked.name() # Inject colouring into the web view. editor._html = re.sub( "(\\.fname\s*\\{)", "\\1 color: {0};".format(textcolour.name()), editor._html) # Fix the default text colour for type answer edit elements. reviewer.Reviewer._css = re.sub( "(#typeans\s*\\{)", "\\1 color: {0};".format(textcolour.name()), reviewer.Reviewer._css)
def initialize(self, mw): log.info("Pinyin Toolkit is initializing") # Build basic objects we use to interface with Anki thenotifier = notifier.AnkiNotifier() themediamanager = mediamanager.AnkiMediaManager(mw) # Open up the database if not self.tryCreateAndLoadDatabase(mw, thenotifier): # Eeek! Database building failed, so we better turn off the toolkit log.error("Database construction failed: disabling the Toolkit") return # Build the updaters updaters = { 'expression' : pinyin.updater.FieldUpdaterFromExpression(thenotifier, themediamanager), 'reading' : pinyin.updater.FieldUpdaterFromReading(), 'meaning' : pinyin.updater.FieldUpdaterFromMeaning(), 'audio' : pinyin.updater.FieldUpdaterFromAudio(thenotifier, themediamanager) } # Finally, build the hooks. Make sure you store a reference to these, because otherwise they # get garbage collected, causing garbage collection of the actions they contain self.hooks = [hookbuilder(mw, thenotifier, themediamanager, updaters) for hookbuilder in hookbuilders] for hook in self.hooks: hook.install() # add hooks and menu items # use wrap() instead of addHook to ensure menu already created def ptkRebuildAddonsMenu(self): ptkMenu = None for menu in self._menus: if menu.title() == "Pinyin Toolkit": ptkMenu = menu break ptkMenu.addSeparator() config = getconfig() hooks.buildHooks(ptkMenu, mw, config, thenotifier, themediamanager, updaters) aqt.addons.AddonManager.rebuildAddonsMenu = wrap(aqt.addons.AddonManager.rebuildAddonsMenu, ptkRebuildAddonsMenu)
def monster(): mw.col.sched.answerCard = wrap( mw.col.sched.answerCard, monsterAnswerCard ) newCount, lrnCount, revCount = mw.col.sched.counts() totalCount = (newCount + lrnCount + revCount) howManyToDo = totalCount / 2 if howManyToDo < N: howManyToDo = N if totalCount < N: howManyToDo = totalCount mw.monstersToDo = howManyToDo mw.monstersDone = 0 # XXX If howManyToDo is > than the number of pngs, this is bad mw.monsters = [ loadMonster(png) for png in os.listdir(MonstersPath)] shuffle(mw.monsters) if mw.monstersToDo > 0: displayMonsters(False) mw.moveToState("review")
# is that the model names are not set up correctly in the # model_buttons list of dictionaries above. cdeck = chooser.deck.decks.current() cdeck['mid'] = m['id'] chooser.deck.decks.save(cdeck) runHook("currentModelChanged") chooser.mw.reset() def isClozeNote(note): for name, val in note.items(): if re.search(r'\{\{c(\d+)::', val): return True return False def newAddCards(self, _old): note = self.editor.note if note.model()['name'] in basic_note_type and isClozeNote(note): oldModelName = note.model()['name'] change_model_to(self.modelChooser, cloze_note_type) _old(self) change_model_to(self.modelChooser, oldModelName) tooltip(_("Automatic switch from Basic to Cloze")) else: return _old(self) AddCards.addCards = wrap(AddCards.addCards, newAddCards, "around")
each other, the class describes this fact. When t and g can't be converted to numbers, the ValueError of that conversion is not caught. """ try: target_value = int(t) given_value = int(g) except ValueError: # No try here. Catch that case higher up. target_value = float(t) given_value = float(g) # One of the two conversions worked: we have two valid numbers, two # ints or two floats. We don’t really care which. if target_value == given_value: return exact_class # Now we know that they are not the same, so either red or yellow. try: factor = 1.0 * given_value / target_value except ZeroDivisionError: return fail_class if factor < 1.0 / pass_factor or factor > pass_factor: return fail_class return pass_class Reviewer.correct = wrap(Reviewer.correct, correct_scalar, "around") old_css = Card.css Card.css = scalar_card_css
if reviewer.state == "question": reviewer._showQuestion() elif reviewer.state == "answer": reviewer._showAnswer() # Catch ctrl key presses from bottom.web. elif url == "EFDRC!ctrldown": reviewer.web.eval("EFDRC.ctrldown()") elif url == "EFDRC!ctrlup": reviewer.web.eval("EFDRC.ctrlup()") elif url == "EFDRC!paste": # From aqt.editor.Editor._onPaste, doPaste. mime = mw.app.clipboard().mimeData(mode=QClipboard.Clipboard) html, internal = editorwv._processMime(mime) html = editorwv.editor._pastePreFilter(html, internal) reviewer.web.eval("pasteHTML(%s, %s);" % (json.dumps(html), json.dumps(internal))) elif url.startswith("EFDRC!debug#"): fld = url.replace("EFDRC!debug#", "") showText(fld) else: return _old(reviewer, url) Reviewer._bottomHTML = wrap(Reviewer._bottomHTML, myRevBottomHTML, "around") Reviewer.revHtml = wrap(Reviewer.revHtml, myRevHtml, "around") Reviewer._linkHandler = wrap(Reviewer._linkHandler, myLinkHandler, "around") addHook("fmod_edit", edit)
from aqt.utils import tooltip from .config import gc, pycmd_string from .helpers import check_string_for_existing_file from .linked__link_handler import process_urlcmd from .open_in_external import open_external def myLinkHandler(self, url, _old): if process_urlcmd(url): return else: return _old(self, url) Reviewer._linkHandler = wrap(Reviewer._linkHandler, myLinkHandler, "around") Previewer._on_bridge_cmd = wrap(Previewer._on_bridge_cmd, myLinkHandler, "around") Editor.onBridgeCmd = wrap(Editor.onBridgeCmd, myLinkHandler, "around") def contexthelper(menu, selectedtext): if not gc("inline_prefix"): return if not gc("inline_prefix") in selectedtext: return file, page = check_string_for_existing_file(selectedtext) # print(f"file_add_to_context: {file}, {page}") if file: a = menu.addAction("Try to open externally") a.triggered.connect(lambda _, f=file, p=page: open_external(f, p))
def setup(): Editor.onBridgeCmd = wrap(Editor.onBridgeCmd, onBridgeCmd, "around") addHook("browser.setupMenus", setup_menus) addHook("setupEditorButtons", setup_editor_buttons)
def initializeScheduler(): for scheduler in SCHEDULERS: scheduler._burySiblings = wrap(scheduler._burySiblings, myBurySiblings, "around")
self.arToggleLabel = QtGui.QLabel("Strip Arabic\n Diacritics") # Initial checked state is what we had saved previously self.arToggleButton.setCheckState(mw.col.conf.get(CONF_KEY_CHECKED, 0)) # Save state on toggle mw.connect(self.arToggleButton, SIGNAL("stateChanged(int)"), onChecked) # Add our items to the right of the search box. We do this by moving # every widget out of the gridlayout and into a new list. We simply # add our stuff in the new list in the right place before moving them # back to gridlayout. n_items = self.gridLayout.count() items= [] for i in range(0, n_items): item = self.gridLayout.itemAt(i).widget() items.append(item) if item == self.searchEdit: items.append(self.arToggleButton) items.append(self.arToggleLabel) for i, item in enumerate(items): self.gridLayout.addWidget(item, 0, i, 1, 1) def onChecked(state): """Save the checked state in Anki's configuration.""" mw.col.conf[CONF_KEY_CHECKED] = state Ui_Dialog.setupUi= wrap(Ui_Dialog.setupUi, mySetupUi) DataModel.search = mySearch
from anki.hooks import wrap, addHook from aqt import mw from aqt.reviewer import Reviewer def newShortcutKeys(self, _old): return _old(self) + [ ("j", lambda: self._answerCard(1)), ("k", lambda: self._answerCard(2)), ("l", lambda: self._answerCard(3)), (";", lambda: self._answerCard(4)), ("x", lambda: self.onSuspendCard()), ] def newAnswerCard(self, ease, _old): if self.state == "question": self._showAnswer() else: _old(self, min(self.mw.col.sched.answerButtons(self.card), ease)) def refocusInterface(): mw.web.setFocus() Reviewer._shortcutKeys = wrap(Reviewer._shortcutKeys, newShortcutKeys, "around") Reviewer._answerCard = wrap(Reviewer._answerCard, newAnswerCard, "around") addHook("showQuestion", refocusInterface) addHook("showAnswer", refocusInterface)
# "good" as an answer for cards studied ahead). # # As the scheduled due date draws closer these intervals will start to # diverge, ever coming closer to the intervals you would see if you # were to review the card when it's actually due ivl2 = int(max(elapsed * 1.2, card.ivl, 1)) # hard (default fct = 1.2) ivl3 = int(max(elapsed * fct, ivl2, 1)) # good ivl4 = int(max(elapsed * fct * conf['ease4'], ivl3, 1)) # easy print("--------------------------------") print("card.ivl", card.ivl) print("elapsed", elapsed) print("delta to due", card.due - self.today) print("fct", fct) print("ivl2", ivl2) print("ivl3", ivl3) print("ivl4", ivl4) if ease == 2: interval = ivl2 elif ease == 3: interval = ivl3 elif ease == 4: interval = ivl4 # interval capped? return min(interval, conf['maxIvl']) Scheduler._nextRevIvl = wrap(Scheduler._nextRevIvl, nextRevIvl, "around")
''' This addon hooks TextImporter (CSV files) to automatically import media files within the same directory. ''' __version__ = '1.0.0' import os import re from aqt import mw from anki.hooks import wrap from anki.importing import TextImporter from anki.media import MediaManager def importNotes(self, notes): mediamanager = MediaManager(mw.col, None) directory = os.path.dirname(self.file) files = os.listdir(directory) regexes = [re.compile(regex) for regex in mediamanager.regexps] for note in notes: for field in note.fields: for regex in regexes: for finding in regex.findall(field): mediafile = finding[-1] if mediafile in files: mediamanager.addFile(directory + '/' + mediafile) TextImporter.importNotes = wrap(TextImporter.importNotes, importNotes)
def on_ipa_language_select(editor, lang): try: alias = LANGUAGES_MAP[lang] except KeyError as e: print(e) showInfo("mist") editor.ipa_lang_alias = "" return False set_default_lang(mw, lang) editor.ipa_lang_alias = alias def init_ipa(editor, *args, **kwargs): # Get the last selected language (or the default language if the user # has never chosen any) previous_lang = get_default_lang(mw) editor.ipa_lang_alias = LANGUAGES_MAP.get(previous_lang, "") def onBridgeCmd(ed, cmd, _old): if not cmd.startswith("shLang"): return _old(ed, cmd) (type, lang) = cmd.split(":") on_ipa_language_select(ed, lang) addHook("setupEditorButtons", on_setup_buttons) Editor.onBridgeCmd = wrap(Editor.onBridgeCmd, onBridgeCmd, "around") Editor.__init__ = wrap(Editor.__init__, init_ipa)
[ actionFunc(did) for did in dynDeckIds ] mw.progress.finish() tooltip("Updated {0} filtered decks.".format(count)) mw.reset() def _handleFilteredDeckButtons(self, url): if url in ["rebuildDyn", "emptyDyn"]: _updateFilteredDecks(url) def _addButtons(self): # There's no clean way to add a button, so hack it in. :( newHtml = "" newButtons = [ [_("Rebuild All"), "rebuildDyn"], [_("Empty All"), "emptyDyn"], ] for newButton in newButtons: newHtml += "<button title='{0}' onclick='py.link(\"{1}\");'>{0}</button>".format(*newButton) html = self.bottom.web.page().mainFrame().toHtml() buttons = re.findall('<button.+</button>', html) self.bottom.draw(''.join(buttons) + newHtml) DeckBrowser._drawButtons = wrap(DeckBrowser._drawButtons, _addButtons, "after") DeckBrowser._linkHandler = wrap(DeckBrowser._linkHandler, _handleFilteredDeckButtons, "after")
clayout.forms[-1]['pform'].frontWeb.setLinkHandler(simple_link_handler) clayout.forms[-1]['pform'].backWeb.setLinkHandler(simple_link_handler) def add_preview_link_handler(browser): u"""Make sure we play the files from the preview window.""" browser._previewWeb.setLinkHandler(simple_link_handler) def reduce_format_qa(self, text): u"""Remove elements with a given class before displaying.""" soup = BeautifulSoup(text) for hide in soup.findAll(True, {'class': re.compile( '\\b' + hide_class_name + '\\b')}): hide.extract() return original_format_qa(self, unicode(soup)) original_review_link_handler = Reviewer._linkHandler Reviewer._linkHandler = review_link_handler_wrapper original_format_qa = DataModel.formatQA DataModel.formatQA = reduce_format_qa old_css = Card.css Card.css = svg_css addHook("mungeQA", play_button_filter) Browser._openPreview = wrap(Browser._openPreview, add_preview_link_handler) CardLayout.addTab = wrap(CardLayout.addTab, add_clayout_link_handler)
TODO: there seems to be no clean way to add a button. I've resorted to copying the body of Overview._renderBottom and adding the link here. Hopefully we can find a better way to do this in the future. """ links = [ ["O", "opts", _("Options")], ] if self.mw.col.decks.current()['dyn']: links.append(["R", "refresh", _("Rebuild")]) links.append(["E", "empty", _("Empty")]) else: links.append(["C", "studymore", _("Custom Study")]) #links.append(["F", "cram", _("Filter/Cram")]) if self.mw.col.sched.haveBuried(): links.append(["U", "unbury", _("Unbury")]) links.append(["L", "resetLimits", _("Reset Limit Increases")]) buf = "" for b in links: if b[0]: b[0] = _("Shortcut key: %s") % shortcut(b[0]) buf += """ <button title="%s" onclick='pycmd("%s")'>%s</button>""" % tuple(b) self.bottom.draw(buf) self.bottom.web.onBridgeCmd = self._linkHandler Overview._renderBottom = wrap(Overview._renderBottom, _renderBottom, "after") Overview._linkHandler = wrap(Overview._linkHandler, _handleResetLimitsButton, "after")
def init(): EditorWebView.dropEvent = wrap(EditorWebView.dropEvent, drop_event, 'around') EditorWebView.onPaste = custom_decorate(EditorWebView.onPaste, paste_event)
clipboard = QApplication.clipboard() # Get the code from the clipboard code = clipboard.text() langAlias = self.codeHighlightLangAlias # Select the lexer for the correct language my_lexer = get_lexer_by_name(langAlias, stripall=True) # Tell pygments that we will be generating HTML without CSS. # HTML without CSS may take more space, but it's self contained. my_formatter = HtmlFormatter(linenos=linenos, noclasses=True, font_size=16) if linenos: pretty_code = "".join([("", "<center>")[center], highlight(code, my_lexer, my_formatter), ("<br>", "</center><br>")[center]]) # TODO: understand why this is neccessary else: pretty_code = "".join([("", "<center>")[center] + "<table><tbody><tr><td>", highlight(code, my_lexer, my_formatter), "</td></tr></tbody></table>" + ("<br>", "</center><br>")[center]]) # These two lines insert a piece of HTML in the current cursor position self.web.eval("document.execCommand('inserthtml', false, %s);" % json.dumps(pretty_code)) editor.Editor.onCodeHighlightLangSelect = onCodeHighlightLangSelect editor.Editor.highlight_code = highlight_code editor.Editor.__init__ = hooks.wrap(editor.Editor.__init__, init_highlighter)
def setupUi(self, Dialog): """Add an option for Stainless Ease at Lapse section on Deckconf dialog.""" try: self.stainlessEase = QtWidgets.QCheckBox(self.tab_2) except NameError: self.stainlessEase = QtGui.QCheckBox(self.tab_2) self.stainlessEase.setText(_("Stainless Ease")) self.gridLayout_2.addWidget(self.stainlessEase, 7, 0, 1, 3) def load_conf(self): """Get the option for Stainless Ease.""" self.conf = self.mw.col.decks.confForDid(self.deck['id']) c = self.conf f = self.form f.stainlessEase.setChecked(c.get("stainlessEase", False)) def save_conf(self): """Save the option for Stainless Ease.""" self.conf['stainlessEase'] = self.form.stainlessEase.isChecked() addHook("leech", reduce_ease) Scheduler._rescheduleLapse = wrap(Scheduler._rescheduleLapse, preserve_ease, 'around') dconf.Ui_Dialog.setupUi = wrap(dconf.Ui_Dialog.setupUi, setupUi) DeckConf.loadConf = wrap(DeckConf.loadConf, load_conf) DeckConf.saveConf = wrap(DeckConf.saveConf, save_conf, 'before')
_old = kwargs.pop("_old") if "parent" in kwargs: parent = kwargs["parent"] elif len(args) > 4: parent = args[4] # Position of 'parent' parameter. else: parent = None if parent == "EFDRCsemiedit": # Don't show progress window when pasting images while in review. myprogress = True mw.app.setOverrideCursor(QCursor(Qt.WaitCursor)) return else: myprogress = False return _old(*args, **kwargs) def myfinish(self, _old): global myprogress if myprogress: myprogress = False self.app.restoreOverrideCursor() return else: return _old(self) ProgressManager.start = wrap(ProgressManager.start, mystart, "around") ProgressManager.finish = wrap(ProgressManager.finish, myfinish, "around")
for i in transcriptions: ui_actions["transcription_"+i]=add_action(i, sm, set_option_constructor("transcription", i), True) sm=m.addMenu(_("Set speech language")) for i in speech_options: ui_actions["speech_"+i]=add_action(i, sm, set_option_constructor("speech", i), True) add_action(_("Fill missing sounds"), m, fill_sounds_logic) add_action(_("Editor Behavior"), m, edit_logic) sm=m.addMenu(_("Help")) ### REMINDER : the website addresses are also available in config.py, in some startup tips. Don't forget to update both. add_action(_("Setup instructions"), sm, lambda : goto_page("https://github.com/ttempe/chinese-support-addon/wiki/Setup-Instructions")) add_action(_("Usage instructions"), sm, lambda : goto_page("https://github.com/ttempe/chinese-support-addon/wiki")) add_action(_("Support forum"), sm, lambda : goto_page("https://groups.google.com/forum/#!msg/anki-addons/YZmzNpmEuaY/OKbqbfGaMA0J")) add_action(_("Report a bug"), sm, lambda : goto_page("https://github.com/ttempe/chinese-support-addon/issues")) add_action(_("About..."), m, lambda : showInfo(u"Chinese support plugin v. " + __init__.__version__ + u"<br>Copyright © 2012 Thomas TEMPÉ and many others.<br><br>Please see source code for additional info.")) add_action(_("Please rate me on Ankiweb!"), m, lambda : goto_page("https://ankiweb.net/shared/addons/")) update_dict_action_checkboxes() aqt.addons.AddonManager.rebuildAddonsMenu = wrap(aqt.addons.AddonManager.rebuildAddonsMenu, myRebuildAddonsMenu) display_next_tip() display_new_version_message() #Check for new version of this plug-in when closing Anki aqt.main.AnkiQt.onClose = wrap(aqt.main.AnkiQt.onClose, check_for_next_version) #Uncomment to force display of next version info (debug) #latest_version="123" #latest_comment = __init__.release_info #chinese_support_config.set_option("next_version_message", 'A new version of <b>Chinese Support Add-on</b> is available.<br> <br>You can download it now through <tt>Tools->Add-ons->Browse and install</tt><br> <br>Add-on code: %s<br> <br><b>Version %s:</div><div>%s</div>' %( __init__.ankiweb_number, latest_version, latest_comment))
from PyQt4.QtCore import SIGNAL from PyQt4.QtGui import QKeySequence, QShortcut from anki.hooks import wrap from aqt import mw from aqt.reviewer import Reviewer __version__ = "1.2.1" mw.other_deck = QShortcut(QKeySequence("Ctrl+w"), mw) mw.other_browse = QShortcut(QKeySequence("Ctrl+f"), mw) def replay_6(self, evt): """ Use “6” and “i” to replay audio. Use the “6” key to replay audio, useful for reviewing with the right hand on the numeric key pad, and the “i” key, useful when reviewing with the left hand on a Dvorak keyboard. """ key = unicode(evt.text()) if key == "6" or key == 'i': self.replayAudio() Reviewer._keyHandler = wrap(Reviewer._keyHandler, replay_6) mw.connect(mw.other_deck, SIGNAL("activated()"), lambda: mw.moveToState("deckBrowser")) mw.connect(mw.other_browse, SIGNAL("activated()"), lambda: mw.onBrowse())
l = lambda s=self, nn=button_item["note_name"]: change_model_to(s, nn) try: s = QShortcut( QKeySequence(_(button_item["shortcut"])), self.widget) except KeyError: pass else: s.connect(s, SIGNAL("activated()"), l) try: b.setFixedWidth(button_item["button_width"]) except KeyError: b.setFixedWidth(default_button_width) bhbl.addWidget(b) self.connect(b, SIGNAL("clicked()"), l) self.addLayout(bhbl) def change_model_to(self, model_name): #mostly just a copy and paste from the bottom of onModelChange() m = self.deck.models.byName(model_name) self.deck.conf['curModel'] = m['id'] cdeck = self.deck.decks.current() cdeck['mid'] = m['id'] self.deck.decks.save(cdeck) runHook("currentModelChanged") self.mw.reset() ModelChooser.setupModels = wrap( ModelChooser.setupModels, setup_model_buttons, "after") ModelChooser.changeModelTo = change_model_to
def setBrowserEditor(browser, c, p): if mw.miaDictionary and mw.miaDictionary.isVisible(): if browser.editor.note: mw.miaDictionary.dict.setCurrentEditor(browser.editor, 'Browser') else: mw.miaDictionary.dict.closeEditor() def checkCurrentEditor(self): if mw.miaDictionary and mw.miaDictionary.isVisible(): mw.miaDictionary.dict.checkEditorClose(self.editor) Browser._onRowChanged = wrap(Browser._onRowChanged, setBrowserEditor) AddCards._reject = wrap(AddCards._reject, checkCurrentEditor) EditCurrent._saveAndClose = wrap(EditCurrent._saveAndClose, checkCurrentEditor) Browser._closeWindow = wrap(Browser._closeWindow, checkCurrentEditor) def addEditActivated(self, event=False): if mw.miaDictionary and mw.miaDictionary.isVisible(): mw.miaDictionary.dict.setCurrentEditor(self.editor, getTarget(type(self).__name__)) bodyClick = '''document.addEventListener("click", function (ev) { pycmd("bodyClick") }, false);'''
nids = mw.col.findNotes("*") for nid in nids: note = mw.col.getNote(nid) if not check_model(note.model()): continue generate_enhanced_cloze(note) note.flush() def setup_menu(self): browser = self menu = browser.form.menuEdit menu.addSeparator() a = menu.addAction('Update Enhanced Clozes') a.setShortcut(QKeySequence(UPDATE_ENHANCED_CLOZE_SHORTCUT)) a.triggered.connect( lambda _, b=browser: update_all_enhanced_clozes_in_browser(b)) def on_save_now(self, callback=None): update_all_enhanced_cloze(self) AddCards.addCards = wrap(AddCards.addCards, on_add_cards, "around") EditCurrent.onSave = wrap(EditCurrent.onSave, on_edit_current_save, "around") Editor.saveNow = wrap(Editor.saveNow, on_save_now, "before") addHook("browser.setupMenus", setup_menu)
links.append( toolbar.create_link("morph", _(name), on_morph_link_clicked, tip=_(details), id="morph")) try: from aqt import gui_hooks gui_hooks.top_toolbar_did_init_links.append(on_top_toolbar_did_init_links) except: # Support for legacy Anki before 2.1.22 def my_centerLinks(self, _old): name, details = getStatsLink() links = [ ["decks", _("Decks"), _("Shortcut key: %s") % "D"], ["add", _("Add"), _("Shortcut key: %s") % "A"], ["browse", _("Browse"), _("Shortcut key: %s") % "B"], ["stats", _("Stats"), _("Shortcut key: %s") % "T"], ["sync", _("Sync"), _("Shortcut key: %s") % "Y"], ["morph", _(name), _(details)], ] return self._linkHTML(links) toolbar.Toolbar._centerLinks = wrap(toolbar.Toolbar._centerLinks, my_centerLinks, 'around')
def onProfileLoaded(): """Monkey-patch Reviewer delayed in order to counteract bad practices in other add-ons that overwrite revHtml and _linkHandler in their entirety""" Reviewer.revHtml = wrap(Reviewer.revHtml, onRevHtml, "around") Reviewer._linkHandler = wrap(Reviewer._linkHandler, linkHandler, "around")
self.form.fieldsArea.setMinimumSize(50, 1) self.form.widget.setMinimumSize(50, 1) self.extremestate = 0 # for toggling views self.advbrowse_uniqueNote_state_original = mw.col.get_config( "advbrowse_uniqueNote", False) val = gc("splitter_bigger", False) if val: #test for old config style that just had True and False if bool(val): val = 20 self.form.splitter.setHandleWidth(val) if pointVersion() < 45: Browser.setupTable = wrap(Browser.setupTable, mysetupTable, "before") else: Browser.setup_table = wrap(Browser.setup_table, mysetupTable, "before") def my_toggle_notes_only(self, arg): if pointVersion() < 45: self.model.beginReset() mw.col.set_config("advbrowse_uniqueNote", arg) self.onSearchActivated() self.model.endReset() else: self.on_table_state_changed(False) def get_splitter_dimension(self):
def customize_addcards(): AddCards.setupButtons = wrap(AddCards.setupButtons, add_query_button, "before")
iconsDir = os.path.join(mw.pm.addonFolder(), 'ffvocdeckbuilder', 'icons') def enableVocabularyBuilderView(self): return def onSetupEditorButtons(self): """Add an a button to the editor to activate the vocabulary deck building mode. """ # 'text' must be non empty otherwise the function tries to find an icon # into the anki path editorButton = self._addButton( "ffvocdeckbuilder", lambda self=self: enableVocabularyBuilderView(self), tip=u"Build language deck...", text=" ", check=True) editorButton.setIcon(QIcon(os.path.join(iconsDir, 'dictionary.png'))) # Remove the empty text to center align the icon editorButton.setText("") def enableDeckBuilderButton(self, val=True): """Disable the editor button when the note type is not 'FF basic vocabulary' """ if val and (self.note.model()['name'] != "FF basic vocabulary"): self._buttons["ffvocdeckbuilder"].setEnabled(False) hooks.addHook("setupEditorButtons", onSetupEditorButtons) editor.Editor.enableButtons = hooks.wrap( editor.Editor.enableButtons, enableDeckBuilderButton)
# randomized card from lrnDayQueue, revQueue and newQueue (if the relevant setting is set) totalCount = newCardCount + self.revCount + self.lrnDayCount if totalCount > 0: rand = random.randint(1, totalCount) if rand <= newCardCount: card = self._getNewCard() elif rand <= newCardCount + self.revCount: card = self._getRevCard() else: card = self._getLrnDayCard() if card: return card # new cards left? card = self._getNewCard() if card: return card # collapse or finish return self._getLrnCard(collapse=True) Scheduler._resetLrnCount = wrap(Scheduler._resetLrnCount, resetLrnCount, 'around') Scheduler._fillLrnDay = wrap(Scheduler._fillLrnDay, fillLrnDay, 'around') Scheduler._getLrnDayCard = wrap(Scheduler._getLrnDayCard, getLrnDayCard, 'around') Scheduler._getCard = wrap(Scheduler._getCard, getCard, 'around')
def linkHandler(self, url, _old): if not url.startswith("open"): return _old(self, url) (cmd, arg) = url.split(":", 1) openFileHandler(arg) def linkInserter(html): return re.sub(regex_link, replacement, html) def onMungeQA(self, buf, _old): buf = _old(self, buf) return linkInserter(buf) def profileLoaded(): """Support for Advanced Previewer""" try: from advanced_previewer.previewer import Previewer except ImportError: return Previewer.linkHandler = wrap( Previewer.linkHandler, linkHandler, "around") addHook("previewerMungeQA", linkInserter) Reviewer._linkHandler = wrap(Reviewer._linkHandler, linkHandler, "around") Reviewer._mungeQA = wrap(Reviewer._mungeQA, onMungeQA, "around") addHook("profileLoaded", profileLoaded)
"<center>", highlight(code, my_lexer, my_formatter), "</center><br>" ]) else: pretty_code = "".join( [highlight(code, my_lexer, my_formatter), "<br>"]) pretty_code = process_html(pretty_code) # These two lines insert a piece of HTML in the current cursor position ed.web.eval("document.execCommand('inserthtml', false, %s);" % json.dumps(pretty_code)) def process_html(html): """Modify highlighter output to address some Anki idiosyncracies""" # 1.) "Escape" curly bracket sequences reserved to Anki's card template # system by placing an invisible html tag inbetween for pattern, replacement in ((r"{{", r"{<!---->{"), (r"}}", r"}<!---->}"), (r"::", r":<!---->:")): html = re.sub(pattern, replacement, html) return html # Hooks and monkey-patches addHook("setupEditorButtons", onSetupButtons) Editor.onBridgeCmd = wrap(Editor.onBridgeCmd, onBridgeCmd, "around") Editor.__init__ = wrap(Editor.__init__, init_highlighter)
def add_preview_link_handler(browser): """Make sure we play the files from the preview window.""" browser._previewWeb.setLinkHandler(simple_link_handler) def reduce_format_qa(self, text): """Remove elements with a given class before displaying.""" soup = BeautifulSoup(text, 'html.parser') for hide in soup.findAll(True, {'class': re.compile( '\\b' + hide_class_name + '\\b')}): hide.extract() return original_format_qa(self, unicode(soup)) original_review_link_handler = Reviewer._linkHandler Reviewer._linkHandler = review_link_handler_wrapper # TODO: hide stuff from the browser again #original_format_qa = DataModel.formatQA #DataModel.formatQA = reduce_format_qa old_css = Card.css Card.css = svg_css addHook("mungeQA", play_button_filter) Browser._openPreview = wrap(Browser._openPreview, add_preview_link_handler) # TODO: fix this #CardLayout.addTab = wrap(CardLayout.addTab, add_clayout_link_handler)
def linkHandler(self, url, _old): if not url.startswith("open"): return _old(self, url) (cmd, arg) = url.split(":", 1) openFileHandler(arg) def linkInserter(html): return re.sub(regex_link, replacement, html) def onMungeQA(self, buf, _old): buf = _old(self, buf) return linkInserter(buf) def profileLoaded(): """Support for Advanced Previewer""" try: from advanced_previewer.previewer import Previewer except ImportError: return Previewer.linkHandler = wrap(Previewer.linkHandler, linkHandler, "around") addHook("previewerMungeQA", linkInserter) Reviewer._linkHandler = wrap(Reviewer._linkHandler, linkHandler, "around") Reviewer._mungeQA = wrap(Reviewer._mungeQA, onMungeQA, "around") addHook("profileLoaded", profileLoaded)
# Mostly just a copy and paste from the bottom of onModelChange() m = chooser.deck.models.byName(model_name) chooser.deck.conf['curModel'] = m['id'] # When you get a “TypeError: 'NoneType' object has no attribute # '__getitem__'” directing you here, the most likely explanation # is that the model names are not set up correctly in the # model_buttons list of dictionaries above. cdeck = chooser.deck.decks.current() cdeck['mid'] = m['id'] chooser.deck.decks.save(cdeck) runHook("currentModelChanged") chooser.mw.reset() def change_deck_to(chooser, deck_name): """Change to deck with name deck_name""" # Well, that is easy. chooser.deck.setText(deck_name) ModelChooser.setupModels = wrap( ModelChooser.setupModels, lambda mc: setup_buttons(mc, model_buttons, "note type", change_model_to), "after") ModelChooser.change_model_to = change_model_to DeckChooser.setupDecks = wrap( DeckChooser.setupDecks, lambda dc: setup_buttons(dc, deck_buttons, "deck", change_deck_to), "after") DeckChooser.change_deck_to = change_deck_to
ah.log.info("your profile is %s" % (ah.settings.profile)) if ah.settings.profile not in ah.config: ah.config[ah.settings.profile] = {} if ah.user_settings["keep_log"]: ah.log.info("adding %s to config dict" % ah.settings.profile) check_unsynced_score() ################# ### Wrap Code ### ################# addHook("profileLoaded", grab_profile) addHook("unloadProfile", save_stats) Reviewer.nextCard = wrap(Reviewer.nextCard, hrpg_realtime, "before") # Insert progress bar into bottom review stats # along with database scoring and realtime habitica routines orig_remaining = Reviewer._remaining def my_remaining(x): if ah.user_settings["keep_log"]: ah.log.debug("Begin function") ret = orig_remaining(x) if ah.user_settings[ "show_progress_bar"] and not ah.settings.hrpg_progbar == "": ret += " : %s" % (ah.settings.hrpg_progbar) if ah.settings.initialized and ah.user_settings["show_mini_stats"]: mini_stats = ah.habitica.compact_habitica_stats()
from aqt import mw from aqt.reviewer import Reviewer from anki.hooks import wrap from aqt.utils import tooltip def keyHandler(self, evt, _old): key = unicode(evt.text()) if key == "$": self.onForget() else: return _old(self, evt) Reviewer._keyHandler = wrap(Reviewer._keyHandler, keyHandler, "around") def onForget(self): self.mw.checkpoint(_("Forget")) self.mw.col.sched.forgetCards( [c.id for c in self.card.note().cards()]) tooltip(_("Note rescheduled as new")) self.mw.reset() Reviewer.onForget = onForget
window = QDialog(mw) window.setWindowTitle(title_text) window.setWindowIcon( QIcon(join(addon_path, 'user_files/images') + "/icon.png")) header = QLabel() header.setAlignment(Qt.AlignCenter) header.setText( "<div style='font-size: {}px; font-family: {};'> {} </div>".format( headerText_fontSize, headerText_fontStyle, header_text)) image = QLabel() image.setAlignment(Qt.AlignCenter) image.setText( "<img src='{}' style='max-height: 450px; max-width: 450px;'>".format( image_folder + image_name)) button = QPushButton(button_text) button.clicked.connect(lambda: window.hide()) layout = QVBoxLayout() if show_header: layout.addWidget(header) if show_image: layout.addWidget(image) layout.addWidget(button) window.setLayout(layout) if not show_image and not show_header: return else: window.exec() Reviewer._showAnswer = wrap(Reviewer._showAnswer, myPopUp, 'after')
if (self.name == "due" or self.name == "reps" or self.name == "times" or self.name == "added" or self.name == "answered" or self.name == "cum" or self.name == "kanji"): #Get the plot we're gonna modify (calling add_subplot() with the params of an existing subplot returns it) theSubplot = self.figureCanvas.fig.add_subplot(111) #Get a list of the plot's tickmarks defaultTickMarks = theSubplot.get_xticks() newTickMarks = [] #Use each of these ticks to create a set of string labels based on date offsets from today nowDate = datetime.datetime.now() for thisTickMark in defaultTickMarks: delta = datetime.timedelta(days=thisTickMark) newdate = nowDate + delta newTickMarks.append( str(int(thisTickMark)) + "\n" + str(newdate.month) + "/" + str(newdate.day) + "/" + str(newdate.year)[2:] ) #And set the plot's labels! theSubplot.set_xticklabels(newTickMarks) #Setup our hooks if not __name__ == "__main__": AdjustableFigure.updateFigure = wrap(AdjustableFigure.updateFigure, hook_overrideLabels, "after") AdjustableFigure.addFigure = wrap(AdjustableFigure.addFigure, hook_overrideLabels, "after")
from aqt import mw from aqt.reviewer import Reviewer from anki.hooks import wrap def keyHandler(self, evt, _old): key = unicode(evt.text()) if key == "z": try:# throws an error on undo -> do -> undo pattern, otherwise works fine mw.onUndo() except: pass elif key in ["j", "k", "l", ";",]: isq = self.state == "question" if isq: self._showAnswerHack() if key == "j": self._answerCard(1) elif key == "k": self._answerCard(2) elif key == "l": self._answerCard(3) elif key == ";": self._answerCard(4) else: return _old(self, evt) else: return _old(self, evt) Reviewer._keyHandler = wrap(Reviewer._keyHandler, keyHandler, "around")
params = urllib.urlencode({"timestamp": data["date"], "value": data["value"], "comment": data["comment"], "auth_token": token}) conn = httplib.HTTPSConnection(base) conn.request("POST", api, params, headers) response = conn.getresponse() if not response.status == 200: raise Exception("transmission failed:", response.status, response.reason, response.read()) conn.close() def beeminderUpdate(obj, _old=None): ret = _old(obj) col = mw.col or mw.syncer.thread.col if col is not None: checkCollection(col) return ret # convert time to timestamp because python sucks def timestamp(time): epoch = datetime.datetime.utcfromtimestamp(0) delta = time - epoch timestamp = "%d" % delta.total_seconds() return timestamp # run update whenever we sync a deck anki.sync.Syncer.sync = wrap(anki.sync.Syncer.sync, beeminderUpdate, "around")
def extscmhash(self, m, _old): "Return a hash of parts of the schema, to check model compatibility." _old(self, m) s = m['css'] for f in m['flds']: s += f['name'] for t in m['tmpls']: s += t['name'] for fmt in ('qfmt', 'afmt'): s += t[fmt] return checksum(s) ModelManager.scmhash = wrap(ModelManager.scmhash, extscmhash, "around") # Stuff used during development ########################################################################## def debug(): card = mw.col.sched.getCard() #showText(str(card.nid), title="anki-extended-scmhash debug output") note = card.note() #showText(str(note.model), title="anki-extended-scmhash debug output") model = note.model() # debugtext = str(model['tmpls'][0]['name'])
def reduce_format_qa(self, text): u"""Remove elements with a given class before displaying.""" soup = BeautifulSoup(text) for hide in soup.findAll(True, {'class': re.compile( '\\b' + hide_class_name + '\\b')}): hide.extract() return original_format_qa(self, unicode(soup)) def copy_arrow(): u"""Copy the image file to the collection.""" if not os.path.exists(os.path.join( mw.col.media.dir(), collection_arrow_name)): shutil.copy( os.path.join(mw.pm.addonFolder(), 'color_icons', original_arrow_name), collection_arrow_name) original_review_link_handler = Reviewer._linkHandler Reviewer._linkHandler = review_link_handler_wrapper original_format_qa = DataModel.formatQA DataModel.formatQA = reduce_format_qa addHook("mungeQA", play_button_filter) Browser._openPreview = wrap(Browser._openPreview, add_preview_link_handler) CardLayout.addTab = wrap(CardLayout.addTab, add_clayout_link_handler) addHook("profileLoaded", copy_arrow)
AgainColor = getUserOption("AgainColor") HardColor = getUserOption("HardColor") GoodColor = getUserOption("GoodColor") EasyColor = getUserOption("EasyColor") #set font size options if getUserOption("button font size") == "S": FONTSIZE = "" elif getUserOption("button font size") == "M": FONTSIZE = "font-size: 16px;" elif getUserOption("button font size") == "L": FONTSIZE = "font-size: 20px;" # show tooltip in according color if len(cB) > 0 : # display the tooltip in an according color if (cB[0][1]=="Again" or "Again" in cB[0][1]): utils.tooltipWithColour(("<div style='color:#3a3a3a;%s'>Again</div>" % (FONTSIZE)), AgainColor, x=x1, y=y, xref=xref, period=time, width=width, height=height) elif (cB[0][1]=="Hard" or "Hard" in cB[0][1]): utils.tooltipWithColour(("<div style='color:#3a3a3a;%s'>Hard</div>" % (FONTSIZE)), HardColor, x=x2, y=y, xref=xref, period=time, width=width, height=height) elif (cB[0][1]=="Good" or "Good" in cB[0][1]): utils.tooltipWithColour(("<div style='color:#3a3a3a;%s'>Good</div>" % (FONTSIZE)), GoodColor, x=x3, y=y, xref=xref, period=time, width=width, height=height) elif (cB[0][1]=="Easy" or "Easy" in cB[0][1]): utils.tooltipWithColour(("<div style='color:#3a3a3a;%s'>Easy</div>" % (FONTSIZE)), EasyColor, x=x4, y=y, xref=xref, period=time, width=width, height=height) else: # default behavior for unforeseen cases tooltip(cB[0][1]) if getUserOption("confirmation", True): Reviewer._answerCard = wrap(Reviewer._answerCard, answerCard_before, "before") Reviewer.CustomAnswerCard = answerCard_before
#ah.habitica.scorecount_on_sync() #scorecount now sent in a background thread after scoring if ah.settings.score_on_sync: score_backlog(True) ah.log.debug("End function") ################# ### Wrap Code ### ################# addHook("profileLoaded", grab_profile) #addHook("sync", ahsync) addHook("unloadProfile", save_stats) #AnkiQt.closeEvent = wrap(AnkiQt.closeEvent, save_stats, "before") Reviewer.nextCard = wrap(Reviewer.nextCard, hrpg_realtime, "before") #Insert progress bar into bottom review stats # along with database scoring and realtime habitica routines orig_remaining = Reviewer._remaining def my_remaining(x): ah.log.debug("Begin function") ret = orig_remaining(x) #if compare_score_to_db(): #hrpg_progbar = make_habit_progbar() #hrpg_realtime() if not ah.settings.hrpg_progbar == "": ret += " : %s" % (ah.settings.hrpg_progbar) if ah.settings.initialized and ah.settings.show_mini_stats: mini_stats = ah.habitica.compact_habitica_stats() if mini_stats: ret += " : %s" % (mini_stats)
# Copyright 2016-2020 Matthew Hayes # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from progress_stats.graphs import progressGraphs import anki.stats from anki.hooks import wrap anki.stats.CollectionStats.easeGraph = \ wrap(anki.stats.CollectionStats.easeGraph, progressGraphs, pos="")