Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

tutro cb selectors done

  • Loading branch information...
commit 16c6e8f97526731c1d8439d2012d45955fb10cb7 1 parent 89d3d81
@baverman authored
View
16 typetrainer/tutors/__init__.py
@@ -2,13 +2,14 @@
from typetrainer.i18n import _
-available_tutors = {
- 'en.basic': _('Basic English'),
- 'en.advanced': _('Advanced English'),
- 'ru.basic': _('Basic Russian'),
-}
+from . import en, ru
+
+available_tutors = (en, ru)
def get_filler(tutor, filename):
+ fullname = tutor
+ tutor, sep, level = tutor.partition('.')
+
package_name = 'typetrainer.tutors.' + tutor
__import__(package_name)
pkg = sys.modules[package_name]
@@ -18,8 +19,11 @@ def get_filler(tutor, filename):
else:
text = _(u'Choose file with words.')
- filler = pkg.get_filler(text, None)
+ filler = pkg.get_filler(text, level)
filler.filename = filename
filler.name = tutor
+ filler.level = level
+ filler.tutor = pkg
+ filler.fullname = fullname
return filler
View
60 typetrainer/tutors/en.py
@@ -0,0 +1,60 @@
+import re
+from .common import Filler
+
+from typetrainer.i18n import _
+
+name = 'en'
+label = _('English')
+
+levels = (
+ ('basic', _('Basic')),
+ ('advanced', _('Advanced')),
+# ('superb', _('Superb')),
+)
+
+def make_lengths_seq(words):
+ for t, w in words:
+ if t == 'w':
+ wlen = len(w)
+ yield 'w', wlen if wlen <= 3 else wlen + 3
+ else:
+ yield t, w
+
+def split_to_words(text, level):
+ filter_non_word = re.compile('(?i)[^a-z\']+')
+
+ charsets = {
+ 'basic': '(?i)[a-z\',]+',
+ 'advanced': '(?i)[a-z\',.:;"]+'
+ }
+
+ if level == 'basic':
+ text = text.lower()
+
+ for word in re.findall(charsets[level], text):
+ non_word_cars = ',.:;"'
+ esym = None
+ for c in non_word_cars:
+ if word.endswith(c):
+ esym = c
+ break
+
+ ssym = '"' if word.startswith('"') else None
+
+ word = filter_non_word.sub('', word).strip("'")
+ if word:
+ if ssym:
+ yield 's', ssym
+ yield 'w', word
+ if esym:
+ yield 's', esym
+
+ yield 's', ' '
+
+def get_filler(text, level):
+ words = list(split_to_words(text, level))
+ if not words:
+ words = list(split_to_words(
+ u'Tutor is empty. Select another or choose appropriate file.',
+ level))
+ return Filler(words, make_lengths_seq)
View
0  typetrainer/tutors/en/__init__.py
No changes.
View
38 typetrainer/tutors/en/advanced.py
@@ -1,38 +0,0 @@
-import re
-from ..common import Filler
-
-def make_lengths_seq(words):
- for t, w in words:
- if t == 'w':
- wlen = len(w)
- yield 'w', wlen if wlen <= 3 else wlen + 3
- else:
- yield t, w
-
-def split_to_words(text):
- filter_non_word = re.compile('(?i)[^a-z\']+')
- for word in re.findall('(?i)[a-z\',.:;"]+', text):
- non_word_cars = ',.:;"'
- esym = None
- for c in non_word_cars:
- if word.endswith(c):
- esym = c
- break
-
- ssym = '"' if word.startswith('"') else None
-
- word = filter_non_word.sub('', word)
- if word:
- if ssym:
- yield 's', ssym
- yield 'w', word
- if esym:
- yield 's', esym
-
- yield 's', ' '
-
-def get_filler(text, options):
- words = list(split_to_words(text))
- if not words:
- words = list(split_to_words(u'Tutor is empty. Select another or choose appropriate file.'))
- return Filler(words, make_lengths_seq)
View
31 typetrainer/tutors/en/basic.py
@@ -1,31 +0,0 @@
-import re
-from ..common import Filler
-
-def make_lengths_seq(words):
- for t, w in words:
- if t == 'w':
- wlen = len(w)
- yield 'w', wlen if wlen <= 3 else wlen + 3
- else:
- yield t, w
-
-def split_to_words(text):
- for word in re.findall('(?i)[a-z\',]+', text.lower()):
- syms = []
- if word.endswith(','):
- syms.append(',')
-
- word = word.replace(',', '').strip("'")
- if word:
- yield 'w', word
- if syms:
- for s in syms:
- yield 's', s
-
- yield 's', ' '
-
-def get_filler(text, options):
- words = list(split_to_words(text))
- if not words:
- words = list(split_to_words(u'Tutor is empty. Select another or choose appropriate file.'))
- return Filler(words, make_lengths_seq)
View
3  typetrainer/tutors/help.py
@@ -30,6 +30,9 @@ def __init__(self, words):
self.chain = make_word_chain(words, self.dist)
self.name = 'help'
self.filename = None
+ self.tutor = None
+ self.fullname = None
+ self.level = None
def get_next_word(self, prev=None):
try:
View
15 typetrainer/tutors/ru/basic.py → typetrainer/tutors/ru.py
@@ -1,6 +1,17 @@
# -*- coding: utf-8 -*-
import re
-from ..common import Filler
+from .common import Filler
+
+from typetrainer.i18n import _
+
+name = 'ru'
+label = _('Russian')
+
+levels = (
+ ('basic', _('Basic')),
+# ('advanced', _('Advanced')),
+# ('superb', _('Superb')),
+)
def make_lengths_seq(words):
for t, w in words:
@@ -25,7 +36,7 @@ def split_to_words(text):
yield 's', ' '
-def get_filler(text, options):
+def get_filler(text, level):
words = list(split_to_words(text))
if not words:
words = list(split_to_words(u'Пустое упражнение. Выберите другое или загрузите '
View
0  typetrainer/tutors/ru/__init__.py
No changes.
View
9 typetrainer/ui/__init__.py
@@ -1,4 +1,5 @@
import gtk, gobject
+import contextlib
def idle_callback(callable, args):
args, kwargs = args
@@ -16,6 +17,14 @@ def refresh_gui():
while gtk.events_pending():
gtk.main_iteration_do(block=False)
+@contextlib.contextmanager
+def block_handler(obj, handler):
+ obj.handler_block_by_func(handler)
+ try:
+ yield
+ finally:
+ obj.handler_unblock_by_func(handler)
+
class BuilderAware(object):
def __init__(self, glade_file):
self.gtk_builder = gtk.Builder()
View
3  typetrainer/ui/kbd.py
@@ -17,6 +17,7 @@
n130_gap = 0.12
n130_keyboard = {
+ 'name': 'n130',
'keys': [
[49, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, backspace],
[tab, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 51],
@@ -52,6 +53,7 @@
}
n130_sdfv_keyboard = n130_keyboard.copy()
+n130_sdfv_keyboard['name'] = 'n130_sdfv'
n130_sdfv_keyboard['zones'] = [
([3, 4, 7, 9, 10, 13], [3, 1, 4, 5, 1, 3, 0]),
([1, 3, 4, 6, 8, 9], [0, 3, 1, 4, 5, 1, 3]),
@@ -64,6 +66,7 @@
]
n130_dvp_keyboard = n130_keyboard.copy()
+n130_dvp_keyboard['name'] = 'n130_dvp'
n130_dvp_keyboard['zones'] = [
([3, 4, 5, 7, 9, 10, 11, 13], [1, 2, 3, 4, 5, 1, 2, 3, 0]),
([1, 2, 3, 4, 6, 8, 9, 10], [0, 1, 2, 3, 4, 5, 1, 2, 3]),
View
47 typetrainer/ui/main.glade
@@ -10,7 +10,6 @@
<property name="window_position">center</property>
<property name="default_width">800</property>
<property name="type_hint">dialog</property>
- <signal name="button_press_event" handler="on_window_button_press_event"/>
<signal name="key_release_event" handler="on_key_event"/>
<signal name="key_press_event" handler="on_key_event"/>
<signal name="delete_event" handler="on_window_delete_event"/>
@@ -96,7 +95,9 @@
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">Tutor</property>
+ <property name="label" translatable="yes">_Tutor</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">tutor_cb</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
@@ -109,7 +110,7 @@
<child>
<object class="GtkComboBox" id="tutor_cb">
<property name="visible">True</property>
- <property name="model">tutor_ls</property>
+ <signal name="changed" handler="on_tutor_cb_changed"/>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
@@ -136,7 +137,9 @@
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">Level</property>
+ <property name="label" translatable="yes">_Level</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">level_cb</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
@@ -149,7 +152,7 @@
<child>
<object class="GtkComboBox" id="level_cb">
<property name="visible">True</property>
- <property name="model">level_ls</property>
+ <signal name="changed" handler="on_level_cb_changed"/>
<child>
<object class="GtkCellRendererText" id="cellrenderertext2"/>
<attributes>
@@ -176,7 +179,9 @@
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">Layout</property>
+ <property name="label" translatable="yes">L_ayout</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">layout_cb</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
@@ -189,7 +194,7 @@
<child>
<object class="GtkComboBox" id="layout_cb">
<property name="visible">True</property>
- <property name="model">layout_ls</property>
+ <signal name="changed" handler="on_layout_cb_changed"/>
<child>
<object class="GtkCellRendererText" id="cellrenderertext3"/>
<attributes>
@@ -220,6 +225,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
+ <signal name="clicked" handler="on_open_bt_clicked"/>
<child>
<object class="GtkLabel" id="label6">
<property name="visible">True</property>
@@ -302,7 +308,8 @@
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
- <property name="label" translatable="yes">Misc</property>
+ <property name="label" translatable="yes">_Misc</property>
+ <property name="use_underline">True</property>
</object>
</child>
</object>
@@ -314,28 +321,4 @@
</object>
</child>
</object>
- <object class="GtkListStore" id="tutor_ls">
- <columns>
- <!-- column-name id -->
- <column type="gchararray"/>
- <!-- column-name name -->
- <column type="gchararray"/>
- </columns>
- </object>
- <object class="GtkListStore" id="level_ls">
- <columns>
- <!-- column-name id -->
- <column type="gchararray"/>
- <!-- column-name name -->
- <column type="gchararray"/>
- </columns>
- </object>
- <object class="GtkListStore" id="layout_ls">
- <columns>
- <!-- column-name id -->
- <column type="gchararray"/>
- <!-- column-name name -->
- <column type="gchararray"/>
- </columns>
- </object>
</interface>
View
139 typetrainer/ui/main.py
@@ -5,15 +5,15 @@
import pango
from typetrainer.i18n import _
-from typetrainer.ui import idle, refresh_gui, BuilderAware
+from typetrainer.ui import idle, refresh_gui, BuilderAware, block_handler
from typetrainer.util import join_to_file_dir
from typetrainer.tutors import available_tutors, get_filler
from typetrainer.ui.kbd import n130_dvp_keyboard, n130_keyboard, n130_sdfv_keyboard
available_keyboards = (
- (n130_keyboard, _('ASDF zones'), 'n130'),
- (n130_sdfv_keyboard, _('SDFV zones'), 'n130_sdfv'),
- (n130_dvp_keyboard, _('Programmer Dvorak zones'), 'n130_dvp'),
+ (n130_keyboard, _('ASDF zones')),
+ (n130_sdfv_keyboard, _('SDFV zones')),
+ (n130_dvp_keyboard, _('Programmer Dvorak zones')),
)
RHYTHM_ERROR_THRESHOLD = 1.7 # Miss value from average time gap between chars
@@ -41,10 +41,23 @@ def __init__(self, config, filler, stat, kbd_drawer):
self.kbd_drawer.set_size_request(-1, 280)
self.kbd_drawer.show()
+ self.tutor_ls = gtk.ListStore(object, str)
+ self.tutor_cb.set_model(self.tutor_ls)
+
+ self.level_ls = gtk.ListStore(str, str)
+ self.level_cb.set_model(self.level_ls)
+
+ self.layout_ls = gtk.ListStore(object, str)
+ self.layout_cb.set_model(self.layout_ls)
+
self.update_title()
+ idle(self.fill_tutors)
+ idle(self.fill_layouts)
+
def fill(self):
self.type_entry.set_text('')
+ self.type_entry.grab_focus()
self.start_time = 0
self.last_insert = 0
@@ -129,8 +142,8 @@ def on_type_entry_activate(self, *args):
accuracy = int((len(self.totype_text) - errors) * 100.0 / len(self.totype_text))
self.stat_lb.set_text('%d / %d%%' % (cpm, accuracy))
- if self.filler.name:
- self.stat.log(self.filler.name, cpm, accuracy)
+ if self.filler.fullname:
+ self.stat.log(self.filler.fullname, cpm, accuracy)
self.fill()
@@ -208,37 +221,46 @@ def on_type_entry_insert_text(self, entry, text, *args):
def on_type_entry_delete_text(self, *args):
self.last_insert = 0
- def on_window_button_press_event(self, window, event):
- if event.button != 3:
- return False
-
- menu = gtk.Menu()
-
- if self.filler.name in available_tutors:
- item = None
- for id, label in available_tutors.items():
- item = gtk.RadioMenuItem(item, label)
- if id == self.filler.name:
- item.set_active(True)
-
- item.connect('activate', self.on_tutor_activate, id)
- menu.append(item)
-
- menu.append(gtk.SeparatorMenuItem())
-
-
- item = None
- for kbd, label, name in available_keyboards:
- item = gtk.RadioMenuItem(item, label)
+ def fill_tutors(self):
+ self.tutor_ls.clear()
+ for tutor in available_tutors:
+ it = self.tutor_ls.append((tutor, tutor.label))
+ if tutor.name == self.filler.name:
+ with block_handler(self.tutor_cb, self.on_tutor_cb_changed):
+ self.tutor_cb.set_active_iter(it)
+
+ self.fill_levels()
+
+ def fill_levels(self, fallback=None):
+ self.level_ls.clear()
+ tutor = self.get_selected_item(self.tutor_cb)
+ if tutor:
+ fit = None
+ ait = None
+ for id, label in tutor.levels:
+ it = self.level_ls.append((id, label))
+ if id == self.filler.level:
+ ait = it
+
+ if id == fallback:
+ fit = it
+
+ if not ait:
+ ait = fit
+
+ if ait:
+ with block_handler(self.level_cb, self.on_level_cb_changed):
+ self.level_cb.set_active_iter(ait)
+
+ def fill_layouts(self):
+ self.layout_ls.clear()
+ for kbd, label in available_keyboards:
+ it = self.layout_ls.append((kbd, label))
if kbd is self.kbd_drawer.kbd:
- item.set_active(True)
-
- item.connect('activate', self.on_keyboard_activate, kbd)
- menu.append(item)
-
- menu.append(gtk.SeparatorMenuItem())
-
+ with block_handler(self.layout_cb, self.on_layout_cb_changed):
+ self.layout_cb.set_active_iter(it)
+ def noop(self):
if 'RECENT_FILES' in self.config and self.config['RECENT_FILES']:
item = None
for fname in self.config['RECENT_FILES']:
@@ -249,19 +271,11 @@ def on_window_button_press_event(self, window, event):
menu.append(gtk.SeparatorMenuItem())
- item = gtk.ImageMenuItem(gtk.STOCK_OPEN)
- item.connect('activate', self.on_open_file_activate)
- menu.append(item)
-
- item = gtk.MenuItem(_(u'_Statistic'))
- item.connect('activate', self.on_stat_activate)
- menu.append(item)
-
menu.show_all()
menu.popup(None, None, None, event.button, event.time)
return True
- def on_open_file_activate(self, item):
+ def on_open_bt_clicked(self, sender):
dialog = gtk.FileChooserDialog(_("Open file..."),
None,
gtk.FILE_CHOOSER_ACTION_OPEN,
@@ -296,24 +310,39 @@ def get_tutor_for_file(self, filename):
return self.config._get_tutor_for_file(filename, tutor)
- def on_tutor_activate(self, item, tutor):
- if item.get_active():
+ def get_selected_item(self, cb, column=0):
+ it = cb.get_active_iter()
+ if it:
+ return cb.get_model().get_value(it, column)
+ else:
+ return None
+
+ def on_tutor_cb_changed(self, sender):
+ tutor = self.get_selected_item(sender)
+ if tutor:
+ self.fill_levels(tutor.levels[0][0])
+ level = self.get_selected_item(self.level_cb)
+ tutor = '%s.%s' % (tutor.name, level)
self.config._set_tutor_for_file(self.filler.filename, tutor)
idle(self.update_filler, tutor, self.filler.filename)
def on_filename_activate(self, item, filename):
idle(self.update_filler, self.get_tutor_for_file(filename), filename)
- def on_keyboard_activate(self, item, kbd):
- if item.get_active():
- for k, label, name in available_keyboards:
- if k is kbd:
- self.config['KEYBOARD'] = name
- break
- else:
- self.config['KEYBOARD'] = None
+ def on_level_cb_changed(self, sender):
+ level = self.get_selected_item(sender)
+ if level:
+ tutor = self.get_selected_item(self.tutor_cb)
+ tutor = '%s.%s' % (tutor.name, level)
+ self.config._set_tutor_for_file(self.filler.filename, tutor)
+ idle(self.update_filler, tutor, self.filler.filename)
+ def on_layout_cb_changed(self, sender):
+ kbd = self.get_selected_item(sender)
+ if kbd:
+ self.config['KEYBOARD'] = kbd['name']
idle(self.kbd_drawer.set_keyboard, kbd)
+ self.type_entry.grab_focus()
def update_title(self):
if self.filler.filename:
@@ -336,4 +365,4 @@ def resize():
self.window.resize(self.window.get_size()[0], self.window.size_request()[1])
return False
- glib.timeout_add(100, resize)
+ glib.timeout_add(200, resize)
Please sign in to comment.
Something went wrong with that request. Please try again.