Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO62
-rw-r--r--balloongame.py94
-rwxr-xr-xlessonbuilder7
-rwxr-xr-xlessons/en_US/MAKELESSONS6
-rw-r--r--lessons/en_US/badwords.txt2
-rw-r--r--lessonscreen.py62
6 files changed, 130 insertions, 103 deletions
diff --git a/TODO b/TODO
index 3fd9d08..5858c1c 100644
--- a/TODO
+++ b/TODO
@@ -1,47 +1,38 @@
Typing Turtle
+Notes
+
+How to handle capitals and punctuation?
+
+Are capitals and punctuation universal concepts? Certainly for all Roman languages.
+Do other languages have capital-like and punctuation-like concepts with different rules?
+Is there a generic way that punctuation could just be handled naturally?
+ It depends on how nicely we want them to work. For example knowing that you put quotes
+ around words, we can randomly enquote words. Knowing that semicolons, periods and
+ commas appear after words also allows us to randomly append them.
+ If we don't care, we can just suggest that a) punctuation be taught after the rest
+ of the alphabet, and b) native text be given which includes plenty of punctuation.
+Is there a generic way that we can handle capitalization?
+ It would be nice to just be able to capitalize the beginning of any word.
+ OTOH, acronyms and stuff would be nice to include and those will only come from
+ wordlists.
+
+The answer to both: Right now, I think it's best to just encourage expansive word lists.
+Note that this means that we have top *stop* stripping non-alpha characters from words
+as we read them in!
+
+BTW, after all that work, when are we going to teach Enter?
+
First Release
-- Write to Loser, Wes about developing artwork.
-- Draw incorrect characters in red.
-- Support backspace, backspace to previous lines.
-- Scrolling TextView in lesson.
-- Missing spaces at the end of some lines thanks to dodgy word wrap.
-- Handle ends of line in a sane manner.
-- Implement two step types: key learning and text copying.
-- Split text into lines for long lessons.
-- Try out an insensitive gtk.Entry instead of the gtk.Label.
-- Better flow at the end of a level. Report the result on the Lesson screen: Need more work, Medal received, etc.
-- Ability of lessons to list medals in other lessons as prerequisites. Disable unavailable lessons.
-- Some sort of lesson sorting criteria.
-- Split into file-per-screen.
-- Scroll lessons list to the first non-medaled lesson at startup. Or just remember scroll position.
+ Status message on the main screen. "You unlocked a new lesson!" for example. Eventually have the turtle 'say' it.
-- Implement a long text copying lesson and fix bugs in the scrolling and typing.
+ Graphical WPM and accuracy meters.
-- WPM meter updated in 1sec timer in addition to on keypress.
-- Working medals assignment: "You got a medal!" popup, display next to lesson.
-- Nice looking keyboard.
-- Highlighted keyboard keys when pressed.
-- Support for displaying modifier keys in Keyboard.
-- Change key shown when modified is held.
-- Indicate next key to press on keyboard.
-- Translate keyboard to native key layout.
+ Make medal WPM adjustable somehow? Perhaps a settable Goal WPM?
+ Highlight regions of keyboard, color by finger.
-+ Artwork and animations.
- + Speed meter picture?
- + Accuracy meter picture?
+ Sound effects.
+ Welcome to the activity sound.
+ Speed up / slow down sounds when WPM crosses threshold: Slow, Medium, Fast.
+ Medal award sounds for each medal type: None, Bronze, Silver, Gold. Applause sound.
+ Incorrect key pressed tick sound.
-+ Develop lessons.
- - Continue to develop lessons for all keys on the keyboard.
- - Develop 'focus' lessons e.g. fj.
- - Mark some lessons as "locational" versus "textual" and translate from the English keyboard to native. Ex: Home row, Left hand, Numbers, etc.
- - Give each lesson criteria for each medal type based on Accuracy, WPM.
-- Automatically generate lessons similar to 'home row' based on a list of keys.
Future Release
+ Goal support with progress reporting. WPM, Accuracy, Entire keyboard learned, etc.
@@ -52,13 +43,6 @@ Future Release
Balloon Game
-- Create BalloonGameScreen class (use gtk.Layout?).
-- Generate a list of random words, or read from lesson dictionary.
-- Score display.
-- Floating balloons with words on them. Random velocities, "floaty" look.
-- Balloon letters disappear when typed.
-- Balloon pops when word typed, score increased.
-- Rate of balloons increases over time.
+ Game finished popup, displays score and medal text.
+ Fix flickering
+ Improve graphics.
diff --git a/balloongame.py b/balloongame.py
index 2550a0b..65ea6f8 100644
--- a/balloongame.py
+++ b/balloongame.py
@@ -23,9 +23,8 @@ import gobject, pygtk, gtk, pango
# parameters about them.
BALLOON_STAGES = [
{ 'count': 10, 'delay': 80 },
-# { 'count': 20, 'delay': 40 },
-# { 'count': 80, 'delay': 20 },
-# { 'count': 100, 'delay': 10 },
+ { 'count': 20, 'delay': 60 },
+ { 'count': 70, 'delay': 40 },
]
class Balloon:
@@ -35,7 +34,8 @@ class Balloon:
self.vx = vx
self.vy = vy
self.word = word
-
+ self.size = 100
+
class BalloonGame(gtk.VBox):
def __init__(self, lesson, activity):
gtk.VBox.__init__(self)
@@ -84,17 +84,17 @@ class BalloonGame(gtk.VBox):
self.finished = False
# Start the animation loop running.
- self.update_timer = gobject.timeout_add(20, self.tick)
+ self.update_timer = gobject.timeout_add(20, self.tick, priority=gobject.PRIORITY_HIGH_IDLE+30)
def realize_cb(self, widget):
self.activity.add_events(gtk.gdk.KEY_PRESS_MASK)
self.key_press_cb_id = self.activity.connect('key-press-event', self.key_cb)
# Clear the mouse cursor.
- #pixmap = gtk.gdk.Pixmap(self.activity.window, 1, 1)
+ #pixmap = gtk.gdk.Pixmap(widget.window, 10, 10)
#color = gtk.gdk.Color()
- #cursor = gtk.gdk.Cursor(pixmap, pixmap, color, color, 0, 0)
- #self.area.window.set_cursor(cursor)
+ #cursor = gtk.gdk.Cursor(pixmap, pixmap, color, color, 5, 5)
+ #widget.window.set_cursor(cursor)
def unrealize_cb(self, widget):
self.activity.disconnect(self.key_press_cb_id)
@@ -124,16 +124,22 @@ class BalloonGame(gtk.VBox):
for b in self.balloons:
if b.word[0] == key:
b.word = b.word[1:]
- self.score += 10
+ self.add_score(10)
# Pop the balloon if it's been typed.
if len(b.word) == 0:
self.balloons.remove(b)
- self.score += 100
+ self.add_score(100)
+
+ self.queue_draw_balloon(b)
+
+ break
return False
def update_balloon(self, b):
+ self.queue_draw_balloon(b)
+
b.x += b.vx
b.y += b.vy
@@ -142,6 +148,8 @@ class BalloonGame(gtk.VBox):
if b.y < -100:
self.balloons.remove(b)
+
+ self.queue_draw_balloon(b)
def tick(self):
if self.finished:
@@ -170,7 +178,7 @@ class BalloonGame(gtk.VBox):
y = self.bounds.height + 100
vx = random.uniform(-2, 2)
- vy = random.uniform(-5, -3)
+ vy = -3 #random.uniform(-5, -3)
b = Balloon(x, y, vx, vy, word)
self.balloons.append(b)
@@ -180,10 +188,8 @@ class BalloonGame(gtk.VBox):
if len(self.balloons) == 0 and self.stage_idx >= len(BALLOON_STAGES):
self.finished = True
+ self.queue_draw()
- #self.queue_draw()
- self.draw()
-
return True
def draw_results(self, gc):
@@ -210,13 +216,20 @@ class BalloonGame(gtk.VBox):
ty = y+h/2-(size[1]/pango.SCALE)/2
self.area.window.draw_layout(gc, tx, ty, layout)
+ def queue_draw_balloon(self, b):
+ x1 = int(b.x - b.size/2)
+ y1 = int(b.y - b.size/2)
+ x2 = int(b.x + b.size/2)
+ y2 = int(b.y + b.size/2)
+ self.queue_draw_area(x1, y1, x2, y2)
+
def draw_balloon(self, gc, b):
x = int(b.x)
y = int(b.y)
# Draw the balloon.
gc.foreground = self.area.get_colormap().alloc_color(65535,0,0)
- self.area.window.draw_arc(gc, True, x-50, y-50, 100, 100, 0, 360*64)
+ self.area.window.draw_arc(gc, True, x-b.size/2, y-b.size/2, b.size, b.size, 0, 360*64)
# Draw the text.
gc.foreground = self.area.get_colormap().alloc_color(0,0,0)
@@ -225,6 +238,37 @@ class BalloonGame(gtk.VBox):
tx = x-(size[0]/pango.SCALE)/2
ty = y-(size[1]/pango.SCALE)/2
self.area.window.draw_layout(gc, tx, ty, layout)
+
+ def add_score(self, num):
+ self.score += num
+ self.queue_draw_score()
+
+ def queue_draw_score(self):
+ layout = self.area.create_pango_layout(_('SCORE: %d') % self.score)
+ layout.set_font_description(pango.FontDescription('Times 14'))
+ size = layout.get_size()
+ x = self.bounds.width-20-size[0]/pango.SCALE
+ y = 20
+ self.queue_draw_area(x, y, x+size[0], y+size[1])
+
+ def draw_score(self, gc):
+ layout = self.area.create_pango_layout(_('SCORE: %d') % self.score)
+ layout.set_font_description(pango.FontDescription('Times 14'))
+ size = layout.get_size()
+ x = self.bounds.width-20-size[0]/pango.SCALE
+ y = 20
+ self.area.window.draw_layout(gc, x, y, layout)
+
+ def draw_instructions(self, gc):
+ # Draw instructions.
+ gc.foreground = self.area.get_colormap().alloc_color(0,0,0)
+
+ layout = self.area.create_pango_layout(_('Type the words to pop the balloons!'))
+ layout.set_font_description(pango.FontDescription('Times 14'))
+ size = layout.get_size()
+ x = (self.bounds.width - size[0]/pango.SCALE)/2
+ y = self.bounds.height-20 - size[1]/pango.SCALE
+ self.area.window.draw_layout(gc, x, y, layout)
def draw(self):
self.bounds = self.area.get_allocation()
@@ -243,23 +287,9 @@ class BalloonGame(gtk.VBox):
self.draw_results(gc)
else:
- # Draw instructions.
- gc.foreground = self.area.get_colormap().alloc_color(0,0,0)
-
- layout = self.area.create_pango_layout(_('Type the words to pop the balloons!'))
- layout.set_font_description(pango.FontDescription('Times 14'))
- size = layout.get_size()
- x = (self.bounds.width - size[0]/pango.SCALE)/2
- y = self.bounds.height-20 - size[1]/pango.SCALE
- self.area.window.draw_layout(gc, x, y, layout)
-
- # Draw score.
- layout = self.area.create_pango_layout(_('SCORE: %d') % self.score)
- layout.set_font_description(pango.FontDescription('Times 14'))
- size = layout.get_size()
- x = self.bounds.width-20-size[0]/pango.SCALE
- y = 20
- self.area.window.draw_layout(gc, x, y, layout)
+ self.draw_instructions(gc)
+
+ self.draw_score(gc)
def expose_cb(self, area, event):
self.draw()
diff --git a/lessonbuilder b/lessonbuilder
index df35fa1..83cc40b 100755
--- a/lessonbuilder
+++ b/lessonbuilder
@@ -202,8 +202,9 @@ def filter_pairs(pairs, required_keys, keys):
return good_pairs
def get_weighted_random_pair(pairs):
- # TODO: I'm currently ignoring the weighting because it's preventing keys from
- # ever appearing, for example j never appears in the home row lesson.
+ # TODO: I'm currently ignoring the weighting because it's preventing certain keys
+ # from ever appearing due to their unpopularity, for example j never appears in the
+ # home row lesson.
return random.choice(pairs)
#n = random.uniform(0, 1)
#for p in pairs:
@@ -387,7 +388,7 @@ def build_intro_steps():
steps = []
text = ''
- text += _('Hihowareyah! Ready to learn the secret of fast typing?\n')
+ text += _('Hihowahyah! Ready to learn the secret of fast typing?\n')
text += _('Always use the correct finger to press each key!\n\n')
text += _('Now, place your hands on the keyboard just like the picture below.\n')
text += _('When you\'re ready, press the SPACE bar with your thumb!')
diff --git a/lessons/en_US/MAKELESSONS b/lessons/en_US/MAKELESSONS
index c5d4718..b5b8a23 100755
--- a/lessons/en_US/MAKELESSONS
+++ b/lessons/en_US/MAKELESSONS
@@ -12,6 +12,7 @@
--desc="This lesson teaches you the a, s, d, f, g, h, j, k and l keys \nin the middle of the keyboard.\nThese keys are called the Home Row." \
--keys="asdfghjkl" \
--wordlist=2of12.txt \
+ --badwordlist=badwords.txt \
--order=1 \
--output=homerow.lesson
@@ -21,6 +22,7 @@
--keys="asdfghjkl" \
--game='balloon' \
--wordlist=2of12.txt \
+ --badwordlist=badwords.txt \
--order=2 \
--output=homerowballoon.lesson
@@ -29,6 +31,7 @@
--desc="This lesson teaches you the q, w, e, r, t, y, u, i, o and p keys \non the top row of the keyboard." \
--keys="qwertyuiop" --base-keys="asdfghjkl" \
--wordlist=2of12.txt \
+ --badwordlist=badwords.txt \
--order=3 \
--output=toprow.lesson
@@ -37,6 +40,7 @@
--desc="This lesson teaches you the z, x, c, v, b, n and m keys \non the bottom row of the keyboard." \
--keys="zxcvbnm" --base-keys="asdfghjklqwertyuiop" \
--wordlist=2of12.txt \
+ --badwordlist=badwords.txt \
--order=4 \
--output=bottomrow.lesson
@@ -47,6 +51,7 @@
--keys="QWERTASDFGZXCVB" \
--base-keys="abcdefghijklmnopqrstuvwxyz" \
--wordlist=2of12.txt \
+ --badwordlist=badwords.txt \
--order=5 \
--output=leftcapital.lesson
@@ -56,5 +61,6 @@
--keys="YUIOPHJKLBNM" \
--base-keys="abcdefghijklmnopqrstuvwxyzQWERTASDFGZXCVB" \
--wordlist=2of12.txt \
+ --badwordlist=badwords.txt \
--order=6 \
--output=rightcapital.lesson
diff --git a/lessons/en_US/badwords.txt b/lessons/en_US/badwords.txt
index 2a549a7..ba09943 100644
--- a/lessons/en_US/badwords.txt
+++ b/lessons/en_US/badwords.txt
@@ -1,2 +1,4 @@
coitus
ass
+re
+ll
diff --git a/lessonscreen.py b/lessonscreen.py
index 7facc55..2fb9435 100644
--- a/lessonscreen.py
+++ b/lessonscreen.py
@@ -112,7 +112,6 @@ class LessonScreen(gtk.VBox):
self.lessontext.set_right_margin(20)
self.lessontext.set_wrap_mode(gtk.WRAP_WORD)
self.lessontext.modify_base(gtk.STATE_NORMAL, self.get_colormap().alloc_color('#ffffcc'))
- #self.lessontext.modify_bg(gtk.STATE_NORMAL, self.get_colormap().alloc_color('#ffff80'))
self.lessonscroll = gtk.ScrolledWindow()
self.lessonscroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
@@ -134,17 +133,11 @@ class LessonScreen(gtk.VBox):
self.connect('unrealize', self.unrealize_cb)
self.show_all()
-
- # Load hand overlay SVGs.
- bundle_path = sugar.activity.activity.get_bundle_path()
- #for o in KEY_OVERLAYS.keys():
- # pass
+
+ self.timer_id = None
self.begin_lesson()
- # Initialize stats update timer.
- gobject.timeout_add(1000, self.timer_cb)
-
def realize_cb(self, widget):
self.activity.add_events(gtk.gdk.KEY_PRESS_MASK|gtk.gdk.KEY_RELEASE_MASK)
self.key_press_cb_id = self.activity.connect('key-press-event', self.key_cb)
@@ -153,33 +146,41 @@ class LessonScreen(gtk.VBox):
def unrealize_cb(self, widget):
self.activity.disconnect(self.key_press_cb_id)
self.activity.disconnect(self.key_release_cb_id)
-
+
+ def start_timer(self):
+ self.start_time = time.time()
+ self.timer_id = gobject.timeout_add(1000, self.timer_cb)
+
+ def stop_timer(self):
+ if self.timer_id:
+ gobject.source_remove(self.timer_id)
+ self.start_time = None
+ self.timer_id = None
+
+ def timer_cb(self):
+ self.update_stats()
+ return True
+
def update_stats(self):
if self.lesson_finished:
return
if self.start_time:
- self.total_time = time.time() - self.start_time
-
- if self.total_time >= 1.0:
- self.wpm = 60 * (self.correct_keys / 5) / self.total_time
- else:
- self.wpm = 1.0
-
+ self.total_time += time.time() - self.start_time
+ self.start_time = time.time()
+
+ if self.total_time >= 1.0:
+ self.wpm = 60 * (self.correct_keys / 5) / self.total_time
self.wpmlabel.set_markup(_('<b>WPM:</b> %(wpm)d') % { 'wpm': int(self.wpm) } )
+
else:
- self.total_time = 0.0
- self.wpm = 100.0
-
+ self.wpm = 1.0
+
if self.total_keys:
self.accuracy = 100.0 * self.correct_keys / self.total_keys
self.accuracylabel.set_markup(_('<b>Accuracy:</b> %(accuracy)d%%') % { 'accuracy' : int(self.accuracy) } )
- def timer_cb(self):
- self.update_stats()
- return True
-
def begin_lesson(self):
self.lesson_finished = False
@@ -190,7 +191,8 @@ class LessonScreen(gtk.VBox):
self.incorrect_keys = 0
self.start_time = None
-
+ self.total_time = 0
+
self.step = None
self.next_step_idx = 0
@@ -216,6 +218,9 @@ class LessonScreen(gtk.VBox):
return new_lines
def advance_step(self):
+ # Stop the WPM timer.
+ self.stop_timer()
+
# Clear step related variables.
self.step = None
@@ -324,7 +329,6 @@ class LessonScreen(gtk.VBox):
self.line_idx = 0
self.begin_line()
-
def begin_line(self):
self.line = self.lines[self.line_idx]
self.line_mark = self.line_marks[self.line_idx]
@@ -373,9 +377,9 @@ class LessonScreen(gtk.VBox):
self.total_keys += 1
elif self.mode == 'text':
- # Timer starts with first text mode keypress.
- if not self.start_time:
- self.start_time = time.time()
+ # WPM timer starts with first text mode keypress.
+ if not self.timer_id:
+ self.start_timer()
# Handle backspace by deleting text and optionally moving up lines.
if key_name == 'BackSpace':