start work on an overview; add flot to resources

This commit is contained in:
Damien Elmes 2011-03-21 16:49:06 +09:00
parent 81d29fedd5
commit c9c7b8c25b
6 changed files with 154 additions and 37 deletions

View file

@ -11,35 +11,6 @@ from anki.utils import fmtTimeSpan
from anki.hooks import addHook from anki.hooks import addHook
import aqt import aqt
_css = """
body { background-color: #eee; }
#outer { margin-top: 1em; }
.sub { color: #555; }
hr { margin:5 0 5 0; border:0; height:1px; background-color:#ddd; }
a:hover { background-color: #aaa; }
a.deck { color: #000; text-decoration: none; font-size: 100%; }
.num { text-align: right; padding: 0 5 0 5; }
a.opts { font-size: 80%; padding: 3; background-color: #ccc;
border-radius: 2px; color: #000; }
td.opts { text-align: right; white-space: nowrap; }
td.menu { text-align: center; }
a { font-size: 80%; text-decoration: none; }
h1 { margin-bottom: 0.2em; }
"""
_body = """
<center>
<div id="outer">
<h1>%(title)s</h1>
%(tb)s
<p>
<table cellspacing=0 cellpadding=0 width=90%%>
%(rows)s
</table>
%(extra)s
</div>
"""
class DeckBrowser(object): class DeckBrowser(object):
"Display a list of remembered decks." "Display a list of remembered decks."
@ -147,28 +118,50 @@ class DeckBrowser(object):
# HTML generation # HTML generation
########################################################################## ##########################################################################
_css = """
.sub { color: #555; }
a.deck { color: #000; text-decoration: none; font-size: 100%; }
.num { text-align: right; padding: 0 5 0 5; }
td.opts { text-align: right; white-space: nowrap; }
td.menu { text-align: center; }
a { font-size: 80%; }
"""
_body = """
<center>
<h1>%(title)s</h1>
%(tb)s
<p>
<table cellspacing=0 cellpadding=0 width=90%%>
%(rows)s
</table>
%(extra)s
</center>
"""
def _renderPage(self): def _renderPage(self):
if self._decks: if self._decks:
buf = "" buf = ""
css = self.mw._sharedCSS + self._css
max=len(self._decks)-1 max=len(self._decks)-1
for c, deck in enumerate(self._decks): for c, deck in enumerate(self._decks):
buf += self._deckRow(c, max, deck) buf += self._deckRow(c, max, deck)
self.web.stdHtml(_body%dict( self.web.stdHtml(self._body%dict(
title=_("Decks"), title=_("Decks"),
rows=buf, rows=buf,
tb=self._toolbar(), tb=self._toolbar(),
extra="<p>%s<p>%s" % ( extra="<p>%s<p>%s" % (
self._summary(), self._summary(),
_("Click a deck to open it, or type a number."))), _("Click a deck to open it, or type a number."))),
_css) css)
else: else:
self.web.stdHtml(_body%dict( self.web.stdHtml(self._body%dict(
title=_("Welcome!"), title=_("Welcome!"),
rows="<tr><td align=center>%s</td></tr>"%_( rows="<tr><td align=center>%s</td></tr>"%_(
"Click <b>Download</b> to get started."), "Click <b>Download</b> to get started."),
extra="", extra="",
tb=self._toolbar()), tb=self._toolbar()),
_css) css)
def _deckRow(self, c, max, deck): def _deckRow(self, c, max, deck):
buf = "<tr>" buf = "<tr>"
@ -212,7 +205,7 @@ class DeckBrowser(object):
# no counts # no counts
buf += "<td colspan=2></td>" buf += "<td colspan=2></td>"
# options # options
buf += "<td class=opts><a class=opts href='opts:%d'>%s&#9660;</a></td>" % ( buf += "<td class=opts><a class=but href='opts:%d'>%s&#9660;</a></td>" % (
c, "Options") c, "Options")
buf += "</tr>" buf += "</tr>"
if c != max: if c != max:

View file

@ -81,6 +81,17 @@ class AnkiQt(QMainWindow):
self.setupEditor() self.setupEditor()
self.setupStudyScreen() self.setupStudyScreen()
_sharedCSS = """
body { background-color: #eee; margin-top: 1em; }
a:hover { background-color: #aaa; }
a.but { font-size: 80%; padding: 3; background-color: #ccc;
border-radius: 2px; color: #000; margin: 0 5 0 5; text-decoration:
none; display: inline-block; }
h1 { margin-bottom: 0.2em; }
hr { margin:5 0 5 0; border:0; height:1px; background-color:#ddd; }
"""
#a { text-decoration: none; }
# State machine # State machine
########################################################################## ##########################################################################

View file

@ -2,10 +2,11 @@
# Copyright: Damien Elmes <anki@ichi2.net> # Copyright: Damien Elmes <anki@ichi2.net>
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html # License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html
import time, os, stat, shutil, difflib import time, os, stat, shutil, difflib, simplejson
import unicodedata as ucd import unicodedata as ucd
from PyQt4.QtCore import * from PyQt4.QtCore import *
from PyQt4.QtGui import * from PyQt4.QtGui import *
from anki.consts import NEW_CARDS_RANDOM
from anki.utils import fmtTimeSpan, stripHTML from anki.utils import fmtTimeSpan, stripHTML
from anki.hooks import addHook, runHook, runFilter from anki.hooks import addHook, runHook, runFilter
from anki.sound import playFromText from anki.sound import playFromText
@ -30,11 +31,118 @@ class Reviewer(object):
self._setupToolbar() self._setupToolbar()
self._reset() self._reset()
# Overview state
##########################################################################
_overviewBody = """
<center>
<h1>%(title)s</h1>
%(table)s
<hr>
<div id="placeholder" style="width:350px; height:100px;"></div>
<span class=sub>%(fcsub)s</span>
<hr>
%(opts)s
</center>
<script id="source" language="javascript" type="text/javascript">
$(function () {
var d = %(fcdata)s;
$.plot($("#placeholder"), [
{ data: d, bars: { show: true, barWidth: 0.8 } }
], {
xaxis: { ticks: [[0.5, "Today"]] }
});
});
</script>
"""
_overviewCSS = """
.due { text-align: right; color: green; }
.new { text-align: right; color: blue; }
.sub { font-size: 80%; color: #555; }
"""
def _overview(self):
css = self.mw._sharedCSS + self._overviewCSS
self.web.stdHtml(self._overviewBody % dict(
title=_("Overview"),
table=self._overviewTable(),
fcsub=_("Due over next two weeks"),
fcdata=self._ovForecast(),
opts=self._ovOpts(),
), css)
def _overviewTable(self):
counts = self._ovCounts()
def but(link, name):
return '<a class=but href="%s">%s</a>' % (link, name)
buf = "<table cellspacing=0 cellpadding=3 width=400>"
buf += "<tr><th></th><th align=right>%s</th>" % _("Due")
buf += "<th align=right>%s</th><th></th></tr>" % _("New")
line = "<tr><td><b>%s</b></td><td class=due>%s</td>"
line += "<td class=new>%s</td><td align=right>%s</td></tr>"
buf += line % (
"<a href=chgrp>%s</a>" % _("Selected Groups"),
counts[0], counts[1],
but("studysel", _("Study")) +
but("cramsel", _("Cram")))
buf += line % (
_("Whole Deck"),
counts[2], counts[3],
but("studyall", _("Study")) +
but("cramall", _("Cram")))
buf += "</table>"
return buf
def _ovCounts(self):
oldNew = self.mw.deck.qconf['newGroups']
oldRev = self.mw.deck.qconf['revGroups']
if not oldNew and not oldRev:
# everything is enabled, no extra work to work to do
self.mw.deck.reset()
allcnt = self.mw.deck.sched.counts()
else:
# need to reset to find all cards
self.mw.deck.qconf['newGroups'] = []
self.mw.deck.qconf['revGroups'] = []
self.mw.deck.reset()
allcnt = self.mw.deck.sched.counts()
self.mw.deck.qconf['newGroups'] = oldNew
self.mw.deck.qconf['revGroups'] = oldRev
self.mw.deck.reset()
selcnt = self.mw.deck.sched.counts()
return [
selcnt[1] + selcnt[2],
selcnt[0],
allcnt[1] + allcnt[2],
allcnt[0],
]
def _ovForecast(self):
return simplejson.dumps(tuple(
enumerate(self.mw.deck.sched.dueForecast(14))))
def _ovOpts(self):
if self.mw.deck.qconf['newCardOrder'] == NEW_CARDS_RANDOM:
ord = _("random")
else:
ord = _("order added")
buf = """
<table width=400>
<tr><td><b>%s</b></td><td align=center>%s</td><td align=right rowspan=2>%s</td></tr>
<tr><td><b>%s</b></td><td align=center>%s</td></tr>
</table>""" % (
_("New cards per day"), self.mw.deck.qconf['newPerDay'],
'<a href=opts class=but>%s</a>' % _("Study Options"),
_("New card order"), ord)
return buf
# State control # State control
########################################################################## ##########################################################################
def _reset(self): def _reset(self):
self.web.stdHtml("") self._overview()
def setState(self, state): def setState(self, state):
"Change to STATE, and update the display." "Change to STATE, and update the display."

View file

@ -66,7 +66,10 @@ class AnkiWebView(QWebView):
QWebView.setHtml(self, html) QWebView.setHtml(self, html)
def stdHtml(self, body, css="", loadCB=None): def stdHtml(self, body, css="", loadCB=None):
self.setHtml(""" self.setHtml("""
<html><head><style>%s</style><script src="qrc:/jquery.min.js"></script></head> <html><head><style>%s</style>
<script src="qrc:/jquery.min.js"></script>
<script src="qrc:/jquery.flot.min.js"></script>
</head>
<body>%s</body></html>""" % (css, body), loadCB) <body>%s</body></html>""" % (css, body), loadCB)
# ensure we're focused # ensure we're focused
self.setFocus() self.setFocus()

View file

@ -95,5 +95,6 @@
<file>icons/view-pim-news.png</file> <file>icons/view-pim-news.png</file>
<file>icons/view_text.png</file> <file>icons/view_text.png</file>
<file>jquery.min.js</file> <file>jquery.min.js</file>
<file>jquery.flot.min.js</file>
</qresource> </qresource>
</RCC> </RCC>

1
designer/jquery.flot.min.js vendored Normal file

File diff suppressed because one or more lines are too long