-
Notifications
You must be signed in to change notification settings - Fork 0
/
flashcards.py
162 lines (123 loc) · 4.62 KB
/
flashcards.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Flash Cards
Author: Paul Goins <[email protected]>
License: GNU GPL v2 or later
"""
from Tkinter import Tk, Frame, Label
import argparse, os, gettext, random
gettext.install("net.vultaire.flashcards")
PROGRAM_NAME=_("Flash Cards")
VERSION="0.2"
class EmptyList(Exception):
pass
class MainWindow(object):
def __init__(self, root, data, interval, font_face, font_size, on_top):
# GUI display
self.root = root
frame = Frame(root)
frame.pack()
font = (font_face, font_size)
self.card = Label(frame, font=font)
self.card.pack()
# Card refresh interval, in seconds
self.refresh_interval = interval
# Data for tracking
self.data = data
self.pending = []
self.current = None
# Update card tracking
self.reset_card()
self.update_card()
if on_top:
self.root.wm_attributes("-topmost", 1)
# Bind events
self.root.bind("<Button-1>", self.flip_forward)
self.root.bind("<Key-Return>", self.flip_forward)
self.root.bind("<Key-space>", self.flip_forward)
self.root.bind("<Button-3>", self.flip_backward)
self.root.bind("<Key-BackSpace>", self.flip_backward)
def reset_card(self):
"""
Resets the pending list of cards.
This method will automatically filter out duplicate entries.
"""
self.pending = list(set(self.data[:]))
def pull_next_card(self):
"""
Pulls the next card from the card list.
This method tracks the current card and will avoid pulling
the same card two times in a row (unless there's only one
card left to pull).
Returns the next card. The value is also set as
self.current.
"""
card = self.current
if len(self.pending) < 1:
raise EmptyList()
elif len(self.pending) == 1:
index = 0
card = self.pending[0]
else:
while card == self.current:
index = random.randint(0, len(self.pending) - 1)
card = self.pending[index]
del self.pending[index]
if len(self.pending) < 1:
self.reset_card()
self.current = card
self.current_index = 0
return card
def update_card(self):
"""
Pulls the next card and updates the GUI.
This is a self-recurring call. It should only be called at
the beginning of the application.
"""
card = self.pull_next_card()
self.card.configure(text=card[0])
refresh_ms = int(self.refresh_interval * 1000)
self.root.after(refresh_ms, self.update_card)
def flip_forward(self, event):
self.current_index = (self.current_index + 1) % len(self.current)
self.card.configure(text=self.current[self.current_index])
def flip_backward(self, event):
self.current_index = (self.current_index - 1) % len(self.current)
self.card.configure(text=self.current[self.current_index])
def parse_args():
ap = argparse.ArgumentParser(
description=_("Randomly displays characters or words in a window, "
"refreshing every 30 seconds or so."))
ap.add_argument("-f", "--font-face", default=None,
help=_("Specify font face."))
ap.add_argument("-s", "--font-size", type=int, default=100,
help=_("Specify font size in points. (Default: %(default)s)"))
ap.add_argument("-i", "--interval", type=int, default=30,
help=_("Specify how long to wait before changing entries. "
"(Default: %(default)s)"))
ap.add_argument("-t", "--on-top", action="store_true", default=False,
help=_("Make the window stay always on top."))
ap.add_argument("-v", "--version", action="store_true", default=False,
help=_("Show version and exit."))
ap.add_argument("filename",
help=_("A UTF-8 encoded file, containing one line per character "
"or word for review."))
return ap.parse_args()
def main():
import sys, csv
options = parse_args()
if options.version:
print "%s v%s" % (PROGRAM_NAME, VERSION)
sys.exit(0)
with open(options.filename) as infile:
reader = csv.reader(infile)
data = [tuple([col.decode("utf-8") for col in row])
for row in reader if len(row) > 0]
root = Tk()
root.title(PROGRAM_NAME)
window = MainWindow(root, data, options.interval, options.font_face,
options.font_size, options.on_top)
root.mainloop()
if __name__ == "__main__":
main()