klavaro  3.13
About: Klavaro is a touch typing tutor program.
  Fossies Dox: klavaro-3.13.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

tutor.c
Go to the documentation of this file.
1 /**************************************************************************/
2 /* Klavaro - a flexible touch typing tutor */
3 /* Copyright (C) 2005-2021 Felipe Emmanuel Ferreira de Castro */
4 /* */
5 /* This file is part of Klavaro, which is a free software: you can */
6 /* redistribute it and/or modify it under the terms of the GNU General */
7 /* Public License as published by the Free Software Foundation, either */
8 /* version 3 of the License, or (at your option) any later version. */
9 /* */
10 /* Klavaro is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
13 /* GNU General Public License for more details (in the file COPYING). */
14 /* You should have received a copy of the GNU General Public License */
15 /* along with Klavaro. If not, see <https://www.gnu.org/licenses/> */
16 /**************************************************************************/
17 
18 /*
19  * Shared tutor window tasks
20  */
21 #include <math.h>
22 #include <string.h>
23 #include <time.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <locale.h>
27 #include <errno.h>
28 #include <glib.h>
29 #include <glib/gstdio.h>
30 #include <gtk/gtk.h>
31 
32 #include "main.h"
33 #include "auxiliar.h"
34 #include "callbacks.h"
35 #include "translation.h"
36 #include "keyboard.h"
37 #include "cursor.h"
38 #include "basic.h"
39 #include "adaptability.h"
40 #include "velocity.h"
41 #include "fluidness.h"
42 #include "accuracy.h"
43 #include "top10.h"
44 #include "tutor.h"
45 
46 extern GtkCssProvider *keyb_css;
47 
48 #define MAX_TOUCH_TICS 4000
49 struct
50 {
53  GTimer *tmr;
54  gdouble elapsed_time;
55  gdouble touch_time[MAX_TOUCH_TICS + 1];
56  guint ttidx;
57  gint n_touchs;
58  gint n_errors;
59  gint retro_pos;
60  gint correcting;
62 
63 struct
64 {
65  struct
66  {
67  double accuracy;
68  double speed;
69  } basic;
70  struct
71  {
72  double accuracy;
73  double speed;
77  } adapt;
78  struct
79  {
80  double accuracy;
81  double speed;
84  double speed_walking;
85  double speed_jogging;
86  double speed_running;
88  double speed_racer;
89  double speed_flying;
90  } velo;
91  struct
92  {
93  double accuracy;
94  double speed;
95  double fluidity;
97  double speed_flying;
98  } fluid;
99 } goal;
100 
101 extern gchar *OTHER_DEFAULT;
102 
103 /*******************************************************************************
104  * Interface functions
105  */
106 TutorType
108 {
109  return (tutor.type);
110 }
111 
112 gchar *
114 {
115  static gchar type_name[4][6] = { "basic", "adapt", "velo", "fluid" };
116 
117  return (type_name[tutor.type]);
118 }
119 
120 gboolean
122 {
123  gchar *code;
124  gboolean is_tibt;
125 
126  if (tutor.type == TT_BASIC || tutor.type == TT_ADAPT)
127  {
129  is_tibt = g_str_equal (code, "bo");
130  g_free (code);
131  return (is_tibt);
132  }
133  else
134  {
135  return (g_str_has_prefix (main_preferences_get_string ("interface", "language"), "bo"));
136  }
137 }
138 
141 {
142  return (tutor.query);
143 }
144 
145 void
147 {
148  tutor.query = query;
149 }
150 
151 gint
153 {
154  if (tutor.type != TT_FLUID)
155  return (FALSE);
156  return (tutor.correcting);
157 }
158 
159 void
161 {
162  tutor.tmr = g_timer_new ();
163 }
164 
165 #define GOAL_GSET(MODULE, GOAL, DEFAULT_VAL) \
166  if (main_preferences_exist ("goals", #MODULE "_" #GOAL))\
167  goal.MODULE.GOAL = (gdouble) main_preferences_get_int ("goals", #MODULE "_" #GOAL);\
168  else\
169  {\
170  goal.MODULE.GOAL = DEFAULT_VAL;\
171  main_preferences_set_int ("goals", #MODULE "_" #GOAL, DEFAULT_VAL);\
172  }
173 #define LEVEL_GSET(MODULE, GOAL, DEFAULT_VAL) \
174  if (main_preferences_exist ("levels", #MODULE "_" #GOAL))\
175  goal.MODULE.GOAL = (gdouble) main_preferences_get_int ("levels", #MODULE "_" #GOAL);\
176  else\
177  {\
178  goal.MODULE.GOAL = DEFAULT_VAL;\
179  main_preferences_set_int ("levels", #MODULE "_" #GOAL, DEFAULT_VAL);\
180  }
181 void
183 {
184  GOAL_GSET (basic, accuracy, 95);
185  GOAL_GSET (basic, speed, 10);
186  GOAL_GSET (adapt, accuracy, 98);
187  GOAL_GSET (adapt, speed, 10);
188  GOAL_GSET (velo, accuracy, 95);
189  GOAL_GSET (velo, speed, 50);
190  GOAL_GSET (fluid, accuracy, 97);
191  GOAL_GSET (fluid, speed, 50);
192  GOAL_GSET (fluid, fluidity, 70);
193 
197 
204  LEVEL_GSET (velo, speed_racer, 80);
206 
209 
210  /*
211  g_printf ("basic accur: %.0f\n", goal.basic.accuracy);
212  g_printf ("basic speed: %.0f\n", goal.basic.speed);
213  g_printf ("adapt accur: %.0f\n", goal.adapt.accuracy);
214  g_printf ("adapt speed: %.0f\n", goal.adapt.speed);
215  g_printf ("velo accur: %.0f\n", goal.velo.accuracy);
216  g_printf ("velo speed: %.0f\n", goal.velo.speed);
217  g_printf ("fluid accur: %.0f\n", goal.fluid.accuracy);
218  g_printf ("fluid speed: %.0f\n", goal.fluid.speed);
219  g_printf ("fluid fluidity: %.0f\n", goal.fluid.fluidity);
220 
221  g_printf ("adapt learning: %.0f\n", goal.adapt.accuracy_learning);
222  g_printf ("adapt improving: %.0f\n", goal.adapt.accuracy_improving);
223  g_printf ("adapt reaching: %.0f\n", goal.adapt.accuracy_reaching);
224 
225  g_printf ("velo crawling: %.0f\n", goal.velo.speed_crawling);
226  g_printf ("velo stepping: %.0f\n", goal.velo.speed_stepping);
227  g_printf ("velo walking: %.0f\n", goal.velo.speed_walking);
228  g_printf ("velo jogging: %.0f\n", goal.velo.speed_jogging);
229  g_printf ("velo running: %.0f\n", goal.velo.speed_running);
230  g_printf ("velo professional: %.0f\n", goal.velo.speed_professional);
231  g_printf ("velo racer: %.0f\n", goal.velo.speed_racer);
232  g_printf ("velo flying: %.0f\n", goal.velo.speed_flying);
233 
234  g_printf ("fluid stumbling: %.0f\n", goal.fluid.fluidity_stumbling);
235  g_printf ("fluid flying: %.0f\n", goal.fluid.speed_flying);
236  */
237 }
238 
239 gdouble
241 {
242  switch (tutor.type)
243  {
244  case TT_BASIC: return goal.basic.accuracy;
245  case TT_ADAPT: return goal.adapt.accuracy;
246  case TT_VELO: return goal.velo.accuracy;
247  case TT_FLUID: return goal.fluid.accuracy;
248  }
249  return -1.0;
250 }
251 
252 gdouble
254 {
255  switch (tutor.type)
256  {
257  case TT_BASIC: return goal.basic.speed;
258  case TT_ADAPT: return goal.adapt.speed;
259  case TT_VELO: return goal.velo.speed;
260  case TT_FLUID: return goal.fluid.speed;
261  }
262  return -1.0;
263 }
264 
265 gdouble
267 {
268  switch (tutor.type)
269  {
270  case TT_BASIC:
271  case TT_ADAPT:
272  case TT_VELO: return 0.0;
273  case TT_FLUID: return goal.fluid.fluidity;
274  }
275  return -1.0;
276 }
277 
278 gdouble
280 {
281  switch (tutor.type)
282  {
283  case TT_ADAPT: if (n > 2) return -1.0; return (&goal.adapt.accuracy_learning) [n];
284  case TT_VELO: if (n > 7) return -2.0; return (&goal.velo.speed_crawling) [n];
285  case TT_FLUID: if (n > 1) return -3.0; return (&goal.fluid.fluidity_stumbling) [n];
286  }
287  return -4.0;
288 }
289 
290 /**********************************************************************
291  * Initialize the course
292  */
293 void
295 {
296  gchar *tmp_title = NULL;
297  gchar *tmp_name = NULL;
298  GtkWidget *wg;
299 
300  gtk_widget_hide (get_wg ("window_main"));
301  gtk_widget_hide (get_wg ("window_keyboard"));
302  gtk_widget_hide (get_wg ("aboutdialog"));
303  gtk_widget_hide (get_wg ("togglebutton_toomuch_errors"));
304  gtk_widget_show (get_wg ("window_tutor"));
305  gtk_widget_grab_focus (get_wg ("entry_mesg"));
306 
307  tutor.type = tt_type;
308  cursor_set_blink (FALSE);
309 
310  /******************************
311  * Set the layout for each exercise type
312  */
313  gtk_widget_hide (get_wg ("button_tutor_top10"));
314  gtk_widget_hide (get_wg ("entry_custom_basic_lesson"));
315  if (tutor.type == TT_BASIC || tutor.type == TT_FLUID)
316  {
317  gtk_widget_show (get_wg ("label_lesson"));
318  gtk_widget_show (get_wg ("spinbutton_lesson"));
319  gtk_widget_show (get_wg ("vseparator_tutor_2"));
320  if (tutor.type == TT_BASIC)
321  {
322  gtk_widget_show (get_wg ("togglebutton_edit_basic_lesson"));
323  gtk_widget_hide (get_wg ("button_tutor_top10"));
324  gtk_widget_show (get_wg ("button_tutor_show_keyb"));
325  gtk_label_set_text (GTK_LABEL (get_wg ("label_lesson")), _("Lesson:"));
326  callbacks_shield_set (TRUE);
327  gtk_spin_button_set_range (GTK_SPIN_BUTTON (get_wg ("spinbutton_lesson")), 1, MAX_BASIC_LESSONS);
328  callbacks_shield_set (FALSE);
329  }
330  else
331  {
332  gtk_widget_hide (get_wg ("togglebutton_edit_basic_lesson"));
333  gtk_widget_show (get_wg ("button_tutor_top10"));
334  gtk_widget_hide (get_wg ("button_tutor_show_keyb"));
335  gtk_label_set_text (GTK_LABEL (get_wg ("label_lesson")), _("Paragraphs:"));
336  callbacks_shield_set (TRUE);
337  gtk_spin_button_set_range (GTK_SPIN_BUTTON (get_wg ("spinbutton_lesson")), 0, 10);
338  callbacks_shield_set (FALSE);
339  }
340  }
341  else
342  {
343  gtk_widget_hide (get_wg ("label_lesson"));
344  gtk_widget_hide (get_wg ("spinbutton_lesson"));
345  gtk_widget_hide (get_wg ("vseparator_tutor_2"));
346  gtk_widget_hide (get_wg ("togglebutton_edit_basic_lesson"));
347  gtk_widget_hide (get_wg ("button_tutor_show_keyb"));
348  gtk_widget_hide (get_wg ("button_tutor_top10"));
349  }
350 
351  if (tutor.type == TT_BASIC || tutor.type == TT_ADAPT)
352  {
353  gtk_widget_hide (get_wg ("button_tutor_other"));
354  gtk_widget_hide (get_wg ("vseparator_tutor_1"));
355  }
356  else
357  {
358  gtk_widget_show (get_wg ("button_tutor_other"));
359  gtk_widget_show (get_wg ("vseparator_tutor_1"));
360  }
361 
362  /******************************
363  * Set decoration texts and tips
364  */
365  switch (tutor.type)
366  {
367  case TT_BASIC:
368  tmp_title = g_strdup (_("Klavaro - Basic Course"));
369  tmp_name = g_strdup ("");
370  break;
371 
372  case TT_ADAPT:
373  tmp_title = g_strdup (_("Klavaro - Adaptability"));
374  tmp_name =
375  g_strdup (_
376  ("Adaptability exercises: automating the fingers"
377  " responses, typing over all the keyboard."));
378  break;
379 
380  case TT_VELO:
381  tmp_title = g_strdup (_("Klavaro - Velocity"));
382  tmp_name = g_strdup (_("Velocity exercises: accelerate typing real words."));
383  break;
384 
385  case TT_FLUID:
386  tmp_title = g_strdup (_("Klavaro - Fluidness"));
387  tmp_name =
388  g_strdup (_("Fluidness exercises: accuracy typing good sense paragraphs."));
389  break;
390  }
391  gtk_window_set_title (get_win ("window_tutor"), tmp_title);
392  wg = get_wg ("label_heading");
393  gtk_label_set_text (GTK_LABEL (wg), tmp_name);
394  g_free (tmp_title);
395  g_free (tmp_name);
396 
397  /******************************
398  * Set tooltips of tutor entry (drag and drop)
399  */
400  if (tutor.type == TT_VELO || tutor.type == TT_FLUID)
401  gtk_widget_set_tooltip_text (get_wg ("entry_mesg"), _("Drag and drop text here to practice with it."));
402  else
403  gtk_widget_set_tooltip_text (get_wg ("entry_mesg"), "");
404 
405  /******************************
406  * Set specific variables
407  */
408  tutor.query = QUERY_INTRO;
409  if (tutor.type == TT_BASIC)
410  {
411  basic_init ();
412  if (basic_get_lesson () > 1)
413  {
414  tutor_process_touch ('\0');
415  return;
416  }
417  }
418  else if (tutor.type == TT_VELO)
419  {
420  velo_init ();
421  }
422  else if (tutor.type == TT_FLUID)
423  {
424  fluid_init ();
425  }
426  tutor_update ();
427 }
428 
429 
430 /**********************************************************************
431  * Update what is shown in the tutor window.
432  */
433 void
435 {
436  switch (tutor.query)
437  {
438  case QUERY_INTRO:
440  break;
441 
442  case QUERY_START:
444  break;
445 
447  break;
448 
449  case QUERY_END:
450  tutor_message (_("End of exercise. Press [Enter] to start another."));
451  break;
452  }
453 }
454 
455 void
457 {
458  gchar *tmp_name;
459  gchar *text;
460  gchar *color_bg;
461  GtkWidget *wg;
462  GtkLabel *wg_label;
463  GtkTextView *wg_text;
464  GtkAdjustment *scroll;
465  GtkTextIter start;
466  GtkTextIter end;
467  GtkStyleContext *sc;
468 
469  if (tutor.type == TT_BASIC)
470  {
471  callbacks_shield_set (TRUE);
472  gtk_spin_button_set_value (GTK_SPIN_BUTTON
473  (get_wg ("spinbutton_lesson")),
474  basic_get_lesson ());
475  callbacks_shield_set (FALSE);
476 
477  wg_label = GTK_LABEL (get_wg ("label_heading"));
478  gtk_label_set_text (wg_label, _("Learning the key positions."));
479  }
480 
481  tutor_message (_("Press any key to start the exercise. "));
482 
483  tmp_name = g_strconcat ("_", tutor_get_type_name (), "_intro.txt", NULL);
484  text = trans_read_text (tmp_name);
485  g_free (tmp_name);
486 
487  wg_text = GTK_TEXT_VIEW (get_wg ("text_tutor"));
488  gtk_text_buffer_set_text (gtk_text_view_get_buffer (wg_text), text, -1);
489  g_free (text);
490 
491  gtk_text_buffer_get_bounds (gtk_text_view_get_buffer (wg_text), &start, &end);
492  gtk_text_buffer_apply_tag_by_name (gtk_text_view_get_buffer (wg_text), "lesson_font", &start, &end);
493  gtk_text_buffer_apply_tag_by_name (gtk_text_view_get_buffer (wg_text), "text_intro", &start, &end);
494 
495  /*
496  * Apply tutor background color and font to the intro
497  */
498  if (main_preferences_exist ("colors", "text_intro_bg"))
499  color_bg = main_preferences_get_string ("colors", "text_intro_bg");
500  else
501  color_bg = g_strdup (TUTOR_WHITE);
502  /* Check if altcolor applies */
503  if (main_altcolor_get_boolean ("colors", "altcolor") == TRUE)
504  {
505  g_free (color_bg);
506  color_bg = main_altcolor_get_string ("colors", "text_intro_bg");
507  }
508  set_wg_bg_color (get_wg ("text_tutor"), color_bg);
509  g_free (color_bg);
510 
511  wg = get_wg ("scrolledwindow_tutor_main");
512  scroll = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (wg));
513  gtk_adjustment_set_value (scroll, 0);
514 
515  callbacks_shield_set (TRUE);
516  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (get_wg ("togglebutton_tutor_intro")), TRUE);
517  callbacks_shield_set (FALSE);
518 }
519 
520 void
522 {
523  gchar *tmp_name;
524  gchar *text;
525  gchar *color_bg;
526  GtkWidget *wg;
527  GtkTextBuffer *buf;
528  GtkTextIter start;
529  GtkTextIter end;
530  GtkAdjustment *scroll;
531 
532  /*
533  * Delete all the text on tutor window
534  */
535  wg = get_wg ("text_tutor");
536  buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (wg));
537  gtk_text_buffer_set_text (buf, "", -1);
538 
539  if (tutor.type == TT_BASIC)
540  {
541  callbacks_shield_set (TRUE);
542  gtk_spin_button_set_value (GTK_SPIN_BUTTON (get_wg ("spinbutton_lesson")),
543  basic_get_lesson ());
544  callbacks_shield_set (FALSE);
545 
546  tmp_name = g_ucs4_to_utf8 (basic_get_char_set (), -1, NULL, NULL, NULL);
547  text = g_strdup_printf ("%s %s", _("Keys:"), tmp_name);
548  g_free (tmp_name);
549  wg = get_wg ("label_heading");
550  gtk_label_set_text (GTK_LABEL (wg), text);
551  g_free (text);
552 
554  }
555 
556  switch (tutor.type)
557  {
558  case TT_BASIC:
559  break;
560  case TT_ADAPT:
562  break;
563  case TT_VELO:
564  if (main_velo_txt ())
566  else
568  break;
569  case TT_FLUID:
571  }
572 
573  /*
574  * Apply tutor background color and font to the text
575  */
576  if (main_preferences_exist ("colors", "char_untouched_bg"))
577  color_bg = main_preferences_get_string ("colors", "char_untouched_bg");
578  else
579  color_bg = g_strdup (TUTOR_CREAM);
580  /* Check if altcolor applies */
581  if (main_altcolor_get_boolean ("colors", "altcolor") == TRUE)
582  {
583  g_free (color_bg);
584  color_bg = main_altcolor_get_string ("colors", "char_untouched_bg");
585  }
586  set_wg_bg_color (get_wg ("text_tutor"), color_bg);
587  g_free (color_bg);
588 
589  gtk_text_buffer_get_bounds (buf, &start, &end);
590  gtk_text_buffer_apply_tag_by_name (buf, "lesson_font", &start, &end);
591  gtk_text_buffer_apply_tag_by_name (buf, "char_untouched", &start, &end);
592 
593  /* Trying to minimize wrapping toggle because of cursor blinking:
594  */
595  end = start;
596  while (gtk_text_iter_forward_word_end (&end))
597  {
598  gtk_text_buffer_apply_tag_by_name (buf, "char_keep_wrap", &start, &end);
599  start = end;
600  if (! gtk_text_iter_forward_char (&end))
601  break;
602  /* This second one seems to not be needed. FIXME ?
603  gtk_text_buffer_apply_tag_by_name (buf, "char_keep_wrap2", &start, &end);
604  */
605  start = end;
606  }
607 
608  if (tutor.type == TT_FLUID)
609  tmp_name = g_strconcat (_("Start typing when you are ready. "), " ",
610  _("Use backspace to correct errors."), " ", NULL);
611  else
612  tmp_name = g_strdup (_("Start typing when you are ready. "));
613 
614  tutor_message (tmp_name);
615  g_free (tmp_name);
616 
617  wg = get_wg ("scrolledwindow_tutor_main");
618  scroll = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (wg));
619  gtk_adjustment_set_value (scroll, 0);
620 
621  callbacks_shield_set (TRUE);
622  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (get_wg ("togglebutton_tutor_intro")), FALSE);
623  callbacks_shield_set (FALSE);
624 }
625 
626 
627 /**********************************************************************
628  * Respond to each touch of the user, according to the tutor.query mode
629  */
630 void
631 tutor_process_touch (gunichar user_chr)
632 {
633  gboolean go_on;
634  gchar *u8ch;
635  GtkTextView *wg_text;
636  GtkTextBuffer *wg_buffer;
637  GtkTextIter start;
638 
639  wg_text = GTK_TEXT_VIEW (get_wg ("text_tutor"));
640  wg_buffer = gtk_text_view_get_buffer (wg_text);
641 
642  switch (tutor.query)
643  {
645  break;
646 
647  case QUERY_INTRO:
648  tutor.query = QUERY_START;
649  tutor_update ();
650  tutor.n_touchs = 0;
651  tutor.n_errors = 0;
652  tutor.retro_pos = 0;
653  tutor.correcting = 0;
654  tutor.ttidx = 0;
655  gtk_text_buffer_get_start_iter (wg_buffer, &start);
656  gtk_text_buffer_place_cursor (wg_buffer, &start);
657  cursor_set_blink (TRUE);
658  cursor_on (NULL);
659  accur_sort ();
660 
661  switch (tutor.type)
662  {
663  case TT_BASIC:
665  tutor_speak_char ();
666  return;
667  case TT_ADAPT:
668  tutor_speak_char ();
669  return;
670  case TT_VELO:
671  tutor_speak_word ();
672  return;
673  case TT_FLUID:
674  return;
675  }
676  return;
677 
678  case QUERY_START:
679  tutor.query = QUERY_PROCESS_TOUCHS;
680  callbacks_shield_set (TRUE);
681  u8ch = g_malloc0 (7);
682  if (g_unichar_to_utf8 (user_chr, u8ch) > 0)
683  tutor_message (u8ch);
684  else
685  tutor_message ("");
686  g_free (u8ch);
687  callbacks_shield_set (FALSE);
688 
689  g_timer_start (tutor.tmr);
690  if (tutor.type == TT_FLUID)
691  tutor_eval_forward_backward (user_chr);
692  else
693  tutor_eval_forward (user_chr);
694 
695  switch (tutor.type)
696  {
697  case TT_BASIC:
699  tutor_speak_char ();
700  return;
701  case TT_ADAPT:
702  tutor_speak_char ();
703  return;
704  case TT_VELO:
705  tutor_speak_word ();
706  return;
707  case TT_FLUID:
708  return;
709  }
710  return;
711 
712  case QUERY_END:
713  if (user_chr == UPSYM)
714  {
716  tutor.query = QUERY_INTRO;
717  tutor_process_touch (L'\0');
718  }
719  else if (user_chr == (gunichar) 8 && tutor.type == TT_BASIC)
720  {
724  tutor.query = QUERY_INTRO;
725  tutor_process_touch (L'\0');
726  }
727  else
728  {
729  tutor_beep ();
730  tutor_update ();
731  }
732  return;
733  }
734 
735  /* It is time to analise the correctness of typing.
736  */
737  if (tutor.type == TT_FLUID)
738  go_on = tutor_eval_forward_backward (user_chr);
739  else
740  go_on = tutor_eval_forward (user_chr);
741 
742  if (go_on == FALSE)
743  {
744  cursor_set_blink (FALSE);
745  cursor_off (NULL);
746  tutor.elapsed_time = g_timer_elapsed (tutor.tmr, NULL);
747 
748  tutor_calc_stats ();
749  tutor.query = QUERY_END;
750  tutor_update ();
751  tutor_beep ();
752  }
753  else
754  {
755  switch (tutor.type)
756  {
757  case TT_BASIC:
758  cursor_on (NULL);
760  tutor_speak_char ();
761  return;
762  case TT_ADAPT:
763  cursor_on (NULL);
764  tutor_speak_char ();
765  return;
766  case TT_VELO:
767  cursor_on (NULL);
768  tutor_speak_word ();
769  return;
770  case TT_FLUID:
771  cursor_off (NULL);
772  return;
773  }
774  }
775 }
776 
777 /**********************************************************************
778  * Advances the cursor one position and test for correctness,
779  * in the shared tutor window.
780  * Updates the variables:
781  * cursor_pos, n_touchs and n_errors.
782  */
783 gboolean
784 tutor_eval_forward (gunichar user_chr)
785 {
786  gunichar real_chr;
787 
788  if (user_chr == L'\b' || user_chr == L'\t')
789  {
790  tutor_beep ();
791  return (TRUE);
792  }
793 
794  gsize n_touchs = g_unichar_fully_decompose (user_chr, FALSE, NULL, 0);
795  tutor.n_touchs += (int) n_touchs;
796 
797  real_chr = cursor_get_char ();
798 
799  // Minimizing the line breaking bug:
800  if (user_chr == UPSYM && real_chr == L' ')
801  user_chr = L' ';
802 
803  /*
804  * Compare the user char with the real char and set the color
805  */
806  if (user_chr == real_chr)
807  {
808  if (tutor.ttidx < MAX_TOUCH_TICS)
809  {
810  tutor.touch_time[tutor.ttidx] =
811  g_timer_elapsed (tutor.tmr, NULL) - tutor.touch_time[tutor.ttidx];
812  tutor.ttidx++;
813  tutor.touch_time[tutor.ttidx] = g_timer_elapsed (tutor.tmr, NULL);
814  if (tutor.type != TT_BASIC)
815  accur_correct (real_chr, tutor.touch_time[tutor.ttidx-1]);
816  }
817  cursor_paint_char ("char_correct");
818  }
819  else
820  {
821  tutor.touch_time[tutor.ttidx] = g_timer_elapsed (tutor.tmr, NULL);
822  if (tutor.type != TT_BASIC)
823  accur_wrong (real_chr);
824  cursor_paint_char ("char_wrong");
825  tutor.n_errors += (int) n_touchs;
826  tutor_beep ();
827  }
828 
829 
830  /*
831  * Go forward and test end of text
832  */
833  if (cursor_advance (1) != 1)
834  return (FALSE);
835 
836  /*
837  * Test end of text
838  */
839  if (cursor_get_char () == L'\n')
840  if (cursor_advance (1) != 1)
841  return (FALSE);
842 
843  return (TRUE);
844 }
845 
846 /**********************************************************************
847  * Like the previous, but allows to go back and forth.
848  */
849 gboolean
850 tutor_eval_forward_backward (gunichar user_chr)
851 {
852  gunichar real_chr;
853 
854  /*
855  * Work on backspaces
856  * L'\t' means an hyper <Ctrl> + <Backspace>
857  */
858  if (user_chr == L'\b' || user_chr == L'\t')
859  {
860  tutor.touch_time[tutor.ttidx] = g_timer_elapsed (tutor.tmr, NULL);
861 
862  /*
863  * Test for end of errors to be corrected
864  */
865  if (tutor.retro_pos == 0)
866  {
867  tutor_beep ();
868  return (TRUE);
869  }
870 
871  /*
872  * Go backwards and test for begin of the text
873  */
874  if (cursor_advance (-1) != -1)
875  {
876  tutor_beep ();
877  return (TRUE);
878  }
879 
880  /*
881  * Test for start of line
882  */
883  if (cursor_get_char () == L'\n')
884  if (cursor_advance (-1) != -1)
885  {
886  tutor_beep ();
887  return (TRUE);
888  }
889 
890  /*
891  * Reinitialize the color (no visible effect at all...)
892  */
893  cursor_paint_char ("char_untouched");
894 
895  /*
896  * Update state
897  */
898  tutor.retro_pos--;
899  tutor.correcting++;
900 
901  if (user_chr == L'\t')
903  return (TRUE);
904  }
905 
906  real_chr = cursor_get_char ();
907 
908  // Minimizing the line-breaking bug:
909  if (user_chr == UPSYM && real_chr == L' ')
910  user_chr = L' ';
911 
912  /*
913  * Compare the user char with the real char and set the color
914  */
915  if (user_chr == real_chr && tutor.retro_pos == 0)
916  {
917  gsize n_touchs = g_unichar_fully_decompose (user_chr, FALSE, NULL, 0);
918  tutor.n_touchs += (int) n_touchs;
919  if (tutor.ttidx < MAX_TOUCH_TICS)
920  {
921  tutor.touch_time[tutor.ttidx] =
922  g_timer_elapsed (tutor.tmr, NULL) - tutor.touch_time[tutor.ttidx];
923  tutor.ttidx++;
924  tutor.touch_time[tutor.ttidx] = g_timer_elapsed (tutor.tmr, NULL);
925  }
926  if (tutor.correcting != 0)
927  {
928  cursor_paint_char ("char_retouched");
929  tutor.n_errors += (int) n_touchs;
930  }
931  else
932  {
933  cursor_paint_char ("char_correct");
934  accur_correct (real_chr, tutor.touch_time[tutor.ttidx-1]);
935  }
936  }
937  else
938  {
939  tutor.touch_time[tutor.ttidx] = g_timer_elapsed (tutor.tmr, NULL);
940  cursor_paint_char ("char_wrong");
941  tutor.retro_pos++;
942  if (tutor.retro_pos == 1)
943  accur_wrong (real_chr);
944  tutor_beep ();
945  }
946 
947  if (tutor.correcting > 0)
948  tutor.correcting--;
949 
950  /*
951  * Go forward and test end of text
952  */
953  if (cursor_advance (1) != 1)
954  {
955  if (tutor.retro_pos == 0)
956  return (FALSE);
957  tutor.retro_pos--;
958  }
959 
960  /*
961  * Test end of paragraph
962  */
963 
964  if (cursor_get_char () == L'\n')
965  if (cursor_advance (1) != 1 && tutor.retro_pos == 0)
966  return (FALSE);
967 
968  return (TRUE);
969 }
970 
971 
972 /**********************************************************************
973  * Calculate the final results
974  */
975 void
977 {
978  guint i = 0;
979  gint minutes;
980  gint seconds;
981  gboolean may_log = TRUE;
982  gdouble accuracy;
983  gdouble touchs_per_second;
984  gdouble velocity;
985  gdouble fluidness;
986  gdouble standard_deviation = 0;
987  gdouble sum;
988  gdouble average = 0;
989  gdouble sample;
990  gchar *contest_ps = NULL;
991  gchar *tmp_locale;
992  gchar *tmp_str = NULL;
993  gchar *tmp_str2 = NULL;
994  gchar *tmp_name;
995  gchar *tmp;
996  FILE *fh;
997  time_t tmp_time;
998  struct tm *ltime;
999  GtkWidget *wg;
1000  GtkTextBuffer *buf;
1001  GtkTextIter start;
1002  GtkTextIter end;
1003  Statistics stat;
1004 
1005  /*
1006  * Calculate statistics
1007  */
1008  minutes = ((gulong) tutor.elapsed_time) / 60;
1009  seconds = ((gulong) tutor.elapsed_time) % 60;
1010 
1011  accuracy = 100 * (1.0 - (gfloat) tutor.n_errors / tutor.n_touchs);
1012  touchs_per_second = (gdouble) (tutor.n_touchs - tutor.n_errors) / tutor.elapsed_time;
1013  velocity = 12 * touchs_per_second;
1014 
1015  /* Average for touch timing
1016  */
1017  sum = 0;
1018  for (i = 2; i < tutor.ttidx; i++)
1019  {
1020  if (tutor.touch_time[i] <= 0)
1021  tutor.touch_time[i] = 1.0e-8;
1022  sample = sqrt (1 / tutor.touch_time[i]);
1023  sum += sample;
1024  }
1025  if (i == 2)
1026  i++;
1027  average = sum / (i - 2);
1028  if (average <= 0)
1029  average = 1.0e-9;
1030 
1031  /* Standard deviation for touch timing
1032  */
1033  sum = 0;
1034  for (i = 2; i < tutor.ttidx; i++)
1035  {
1036  sample = sqrt (1 / tutor.touch_time[i]);
1037  sum += (sample - average) * (sample - average);
1038  }
1039  if (i < 4)
1040  i = 4;
1041  standard_deviation = sqrt (sum / (i - 3));
1042 
1043  /* "Magic" fluidness calculation
1044  */
1045  fluidness = 100 * (1 - standard_deviation / average);
1046  if (fluidness < 2)
1047  fluidness = 2;
1048  stat.score = 0;
1049 
1050  /* Verify if logging is allowed
1051  */
1052  may_log = TRUE;
1053  if (tutor.type == TT_FLUID)
1054  if (tutor.n_touchs < MIN_CHARS_TO_LOG)
1055  {
1056  gdk_display_beep (gdk_display_get_default ());
1057  contest_ps = g_strdup_printf (_("ps.: logging not performed for this session: "
1058  "the number of typed characters (%i) must be greater than %i."),
1059  tutor.n_touchs, MIN_CHARS_TO_LOG);
1060  may_log = FALSE;
1061  }
1062  if (may_log)
1063  {
1064  /*
1065  * Changing to "C" locale: remember to copy the previous value!
1066  */
1067  tmp_locale = g_strdup (setlocale (LC_NUMERIC, NULL));
1068  if (tmp_locale != NULL)
1069  setlocale (LC_NUMERIC, "C");
1070 
1071  /* Logging
1072  */
1073  tmp_name =
1074  g_strconcat (main_path_stats (), G_DIR_SEPARATOR_S "stat_", tutor_get_type_name (), ".txt",
1075  NULL);
1076  assert_user_dir ();
1077  if (!(fh = (FILE *) g_fopen (tmp_name, "r")))
1078  {
1079  fh = (FILE *) g_fopen (tmp_name, "w");
1080  if (tutor.type == TT_BASIC)
1081  fprintf (fh, "Accuracy\tVelocity\tFluidness\tDate\tHour\tLesson\tKeyboard\n");
1082  else if (tutor.type == TT_ADAPT)
1083  fprintf (fh, "Accuracy\tVelocity\tFluidness\tDate\tHour\tKeyboard\tLanguage\n");
1084  else
1085  fprintf (fh, "Accuracy\tVelocity\tFluidness\tDate\tHour\tLesson\tLanguage\n");
1086  }
1087  else
1088  {
1089  fclose (fh);
1090  fh = (FILE *) g_fopen (tmp_name, "a");
1091  }
1092  if (fh)
1093  {
1094  tmp_time = time (NULL);
1095  ltime = localtime (&tmp_time);
1096  fprintf (fh,
1097  "%.2f\t%.2f\t%.2f\t%i-%2.2i-%2.2i\t%2.2i:%2.2i\t",
1098  accuracy, velocity, fluidness,
1099  (ltime->tm_year) + 1900, (ltime->tm_mon) + 1,
1100  (ltime->tm_mday), (ltime->tm_hour), (ltime->tm_min));
1101  switch (tutor.type)
1102  {
1103  case TT_BASIC:
1104  fprintf (fh, "%2.2i\t", basic_get_lesson ());
1105  break;
1106  case TT_ADAPT:
1107  tmp = g_strdup (keyb_get_name ());
1108  for (i=0; tmp[i]; i++)
1109  tmp[i] = (tmp[i] == ' ') ? '_' : tmp[i];
1110  fprintf (fh, "%s\t", tmp);
1111  g_free (tmp);
1112  break;
1113  case TT_VELO:
1114  tmp = g_strdup (velo_get_dict_name ());
1115  for (i=0; tmp[i]; i++)
1116  tmp[i] = (tmp[i] == ' ') ? '_' : tmp[i];
1117  fprintf (fh, "%s\t", tmp);
1118  g_free (tmp);
1119  break;
1120  case TT_FLUID:
1121  tmp = g_strdup (fluid_get_paragraph_name ());
1122  for (i=0; tmp[i]; i++)
1123  tmp[i] = (tmp[i] == ' ') ? '_' : tmp[i];
1124  fprintf (fh, "%s\t", tmp);
1125  g_free (tmp);
1126  break;
1127  }
1128 
1129  if (tutor.type == TT_BASIC)
1130  {
1131  tmp = g_strdup (keyb_get_name ());
1132  for (i=0; tmp[i]; i++)
1133  tmp[i] = (tmp[i] == ' ') ? '_' : tmp[i];
1134  fprintf (fh, "%s\n", tmp );
1135  g_free (tmp);
1136  }
1137  else
1138  fprintf (fh, "%s\n", trans_get_current_language ());
1139 
1140  fclose (fh);
1141  }
1142  else
1143  g_message ("not able to log on this file:\n %s", tmp_name);
1144  g_free (tmp_name);
1145 
1146  /* Log the touch times deviation results of the last session
1147  */
1148  tmp_name = g_strconcat (main_path_stats (), G_DIR_SEPARATOR_S, "deviation_",
1149  tutor_get_type_name (), ".txt", NULL);
1150  if ((fh = (FILE *) g_fopen (tmp_name, "w")))
1151  {
1152  g_message ("writing touch timing deviation results at:\n %s", tmp_name);
1153  fprintf (fh, "i\tdt(i)\t1/sqrt(dt(i))\tAver: %g\tStd: %g\tFluidity: %g\n", average, standard_deviation, fluidness);
1154  for (i = 1; i < tutor.ttidx; i++)
1155  fprintf (fh, "%i\t%g\t%g\n", i, tutor.touch_time[i],
1156  1.0 / sqrt(tutor.touch_time[i] > 0 ? tutor.touch_time[i] : 1.0e-9));
1157  fclose (fh);
1158  }
1159  else
1160  g_message ("not able to log on this file:\n %s", tmp_name);
1161  g_free (tmp_name);
1162 
1163  /* Fluidity specific results
1164  */
1165  if (tutor.type == TT_FLUID)
1166  {
1167  /* Add results to Top 10
1168  */
1169  tmp_name = main_preferences_get_string ("interface", "language");
1170  stat.lang[0] = ((tmp_name[0] == 'C') ? 'e' : tmp_name[0]);
1171  stat.lang[1] = ((tmp_name[0] == 'C') ? 'n' : tmp_name[1]);
1172  stat.genv = (UNIX_OK ? 'x' : 'w');
1173  stat.when = time (NULL);
1174  stat.nchars = tutor.n_touchs;
1175  stat.accur = accuracy;
1176  stat.velo = velocity;
1177  stat.fluid = fluidness;
1178  stat.score = top10_calc_score (&stat);
1179 
1180  g_free (tmp_name);
1181  tmp = main_preferences_get_string ("tutor", "keyboard");
1182  tmp_name = g_strdup_printf ("%s [%s]", g_get_real_name (), tmp);
1183  g_free (tmp);
1184  stat.name_len = strlen (tmp_name);
1185  if (stat.name_len > MAX_NAME_LEN)
1186  stat.name_len = MAX_NAME_LEN;
1187  strncpy (stat.name, tmp_name, stat.name_len + 1);
1188  g_free (tmp_name);
1189 
1190  top10_read_stats (LOCAL, -1);
1192  {
1193  if (top10_validate_stat (&stat))
1194  {
1195  if (top10_compare_insert_stat (&stat, LOCAL))
1196  {
1197  contest_ps = g_strdup (_("ps.: you have entered the Top 10 list, great!"));
1198  top10_write_stats (LOCAL, -1);
1199  if (main_preferences_get_boolean ("game", "autopublish"))
1200  {
1203  top10_global_publish (NULL);
1204  }
1205  }
1206  }
1207  else
1208  contest_ps = g_strdup (":-P");
1209  }
1210  else
1211  contest_ps = g_strdup (_("ps.: the text you just typed doesn't seem to be similar"
1212  " to ordinary texts in the language currently selected:"
1213  " we can't account for it in the 'Top 10' contest."));
1214 
1215  /* Anyway, log also the scoring
1216  */
1217  tmp_name = g_build_filename (main_path_stats (), "scores_fluid.txt", NULL);
1218  assert_user_dir ();
1219  if (!g_file_test (tmp_name, G_FILE_TEST_IS_REGULAR))
1220  {
1221  fh = (FILE *) g_fopen (tmp_name, "w");
1222  fprintf (fh, "Score\tDate\tTime\t# chars\tLang\n");
1223  }
1224  else
1225  fh = (FILE *) g_fopen (tmp_name, "a");
1226  if (fh)
1227  {
1228  ltime = localtime (&stat.when);
1229  fprintf (fh,
1230  "%3.3f\t%i-%2.2i-%2.2i\t%2.2i:%2.2i\t%i\t%s\n",
1231  stat.score, (ltime->tm_year) + 1900, (ltime->tm_mon) + 1,
1232  (ltime->tm_mday), (ltime->tm_hour), (ltime->tm_min),
1234  fclose (fh);
1235  }
1236  else
1237  g_message ("not able to log on this file:\n %s", tmp_name);
1238  g_free (tmp_name);
1239  }
1240 
1241  /* Coming back to the right locale
1242  */
1243  if (tmp_locale != NULL)
1244  {
1245  setlocale (LC_NUMERIC, tmp_locale);
1246  g_free (tmp_locale);
1247  }
1248  }
1249 
1250  /* Print statistics
1251  */
1252  wg = get_wg ("text_tutor");
1253  buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (wg));
1254 
1255  /* Begin the accuracy */
1256  tmp_str = g_strconcat ("\n", _("STATISTICS"), "\n",
1257  _("Elapsed time:"), " %i ",
1258  dngettext (PACKAGE, "minute and", "minutes and", minutes),
1259  " %i ", dngettext (PACKAGE, "second", "seconds", seconds),
1260  "\n", _("Error ratio:"), " %i/%i\n", _("Accuracy:"), " ", NULL);
1261 
1262  tmp_str2 = g_strdup_printf (tmp_str, minutes, seconds, tutor.n_errors, tutor.n_touchs);
1263  g_free (tmp_str);
1264  gtk_text_buffer_insert_at_cursor (buf, tmp_str2, strlen (tmp_str2));
1265 
1266  /* Paint the accuracy */
1267  g_free (tmp_str2);
1268  tmp_str2 = g_strdup_printf ("%.1f%%", accuracy);
1269  gtk_text_buffer_insert_at_cursor (buf, tmp_str2, strlen (tmp_str2));
1270 
1271  gtk_text_buffer_get_end_iter (buf, &start);
1272  gtk_text_buffer_get_end_iter (buf, &end);
1273  gtk_text_iter_backward_cursor_positions (&start, strlen (tmp_str2));
1274  if (accuracy > tutor_goal_accuracy ())
1275  gtk_text_buffer_apply_tag_by_name (buf, "char_correct", &start, &end);
1276  else
1277  gtk_text_buffer_apply_tag_by_name (buf, "char_wrong", &start, &end);
1278 
1279  // Finish the accuracy
1280  g_free (tmp_str2);
1281  tmp_str2 = g_strdup_printf ("\t\t%s %.0f%%\n", _("Goal:"), tutor_goal_accuracy ());
1282  gtk_text_buffer_insert_at_cursor (buf, tmp_str2, strlen (tmp_str2));
1283 
1284  if (tutor.type == TT_VELO || tutor.type == TT_FLUID)
1285  {
1286  // Begin the CPS
1287  g_free (tmp_str2);
1288  tmp_str2 = g_strdup_printf ("%s ", _("Characters per second:"));
1289  gtk_text_buffer_insert_at_cursor (buf, tmp_str2, strlen (tmp_str2));
1290 
1291  // Paint the CPS
1292  g_free (tmp_str2);
1293  tmp_str2 = g_strdup_printf ("%.2f", velocity / 12);
1294  gtk_text_buffer_insert_at_cursor (buf, tmp_str2, strlen (tmp_str2));
1295 
1296  gtk_text_buffer_get_end_iter (buf, &start);
1297  gtk_text_buffer_get_end_iter (buf, &end);
1298  gtk_text_iter_backward_cursor_positions (&start, strlen (tmp_str2));
1299  if (velocity > tutor_goal_speed ())
1300  gtk_text_buffer_apply_tag_by_name (buf, "char_correct", &start, &end);
1301  else
1302  gtk_text_buffer_apply_tag_by_name (buf, "char_wrong", &start, &end);
1303 
1304  // Finish the CPS
1305  g_free (tmp_str2);
1306  tmp_str2 = g_strdup_printf ("\t\t%s %.1f %s\n", _("Goal:"), tutor_goal_speed () / 12, _("(CPS)"));
1307  gtk_text_buffer_insert_at_cursor (buf, tmp_str2, strlen (tmp_str2));
1308 
1309  // Begin the WPM
1310  g_free (tmp_str2);
1311  tmp_str2 = g_strdup_printf ("%s ", _("Words per minute:"));
1312  gtk_text_buffer_insert_at_cursor (buf, tmp_str2, strlen (tmp_str2));
1313 
1314  // Paint the WPM
1315  g_free (tmp_str2);
1316  tmp_str2 = g_strdup_printf ("%.1f", velocity);
1317  gtk_text_buffer_insert_at_cursor (buf, tmp_str2, strlen (tmp_str2));
1318 
1319  gtk_text_buffer_get_end_iter (buf, &start);
1320  gtk_text_buffer_get_end_iter (buf, &end);
1321  gtk_text_iter_backward_cursor_positions (&start, strlen (tmp_str2));
1322  if (velocity > tutor_goal_speed ())
1323  gtk_text_buffer_apply_tag_by_name (buf, "char_correct", &start, &end);
1324  else
1325  gtk_text_buffer_apply_tag_by_name (buf, "char_wrong", &start, &end);
1326 
1327  // Finish the WPM
1328  g_free (tmp_str2);
1329  tmp_str2 = g_strdup_printf ("\t\t%s %.0f %s\n", _("Goal:"), tutor_goal_speed (), _("(WPM)"));
1330  gtk_text_buffer_insert_at_cursor (buf, tmp_str2, strlen (tmp_str2));
1331 
1332  if (tutor.type == TT_FLUID)
1333  {
1334  // Begin the fluidity
1335  g_free (tmp_str2);
1336  tmp_str2 = g_strdup_printf ("%s ", _("Fluidness:"));
1337  gtk_text_buffer_insert_at_cursor (buf, tmp_str2, strlen (tmp_str2));
1338 
1339  // Paint the fluidity
1340  g_free (tmp_str2);
1341  tmp_str2 = g_strdup_printf ("%.1f%%", fluidness);
1342  gtk_text_buffer_insert_at_cursor (buf, tmp_str2, strlen (tmp_str2));
1343 
1344  gtk_text_buffer_get_end_iter (buf, &start);
1345  gtk_text_buffer_get_end_iter (buf, &end);
1346  gtk_text_iter_backward_cursor_positions (&start, strlen (tmp_str2));
1347  if (fluidness > tutor_goal_fluidity ())
1348  gtk_text_buffer_apply_tag_by_name (buf, "char_correct", &start, &end);
1349  else
1350  gtk_text_buffer_apply_tag_by_name (buf, "char_wrong", &start, &end);
1351 
1352  // Finish the fluidity and scores
1353  g_free (tmp_str2);
1354  tmp_str2 = g_strdup_printf ("\t\t%s %.0f%%\n%s: %f\n",
1355  _("Goal:"), tutor_goal_fluidity (),
1356  _("Score"), stat.score);
1357  gtk_text_buffer_insert_at_cursor (buf, tmp_str2, strlen (tmp_str2));
1358  }
1359  }
1360 
1361  // Begin the comments
1362  g_free (tmp_str2);
1363  tmp_str2 = g_strdup_printf ("\n%s\n", _("Comments:"));
1364  gtk_text_buffer_insert_at_cursor (buf, tmp_str2, strlen (tmp_str2));
1365 
1366  switch (tutor.type)
1367  {
1368  case TT_BASIC:
1370  break;
1371  case TT_ADAPT:
1373  break;
1374  case TT_VELO:
1375  velo_comment (accuracy, velocity);
1376  break;
1377  case TT_FLUID:
1378  fluid_comment (accuracy, velocity, fluidness);
1379  if (contest_ps != NULL)
1380  {
1381  gtk_text_buffer_insert_at_cursor (buf, "\n", 1);
1382  gtk_text_buffer_insert_at_cursor (buf, contest_ps, strlen (contest_ps));
1383  g_free (contest_ps);
1384  }
1385  break;
1386  }
1387  g_free (tmp_str2);
1388 
1389  /* This is needed to repaint the final comments with normal black foreground. */
1390  gtk_text_buffer_get_bounds (buf, &start, &end);
1391  gtk_text_buffer_apply_tag_by_name (buf, "char_keep_wrap", &start, &end);
1392 
1393  gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (wg), gtk_text_buffer_get_insert (buf));
1394 }
1395 
1396 /**********************************************************************
1397  * Ensure the user is not trying to type with weird texts in the fluidness contest
1398  */
1399 #define DECEIVENESS_LIMIT 0.205
1400 gboolean
1402 {
1403  guint i, j;
1404  gfloat deceiveness;
1405  gchar *tmp_code;
1406  gchar *tmp_name;
1407 
1408  struct MODEL
1409  {
1410  gchar *text;
1411  Char_Distribution dist;
1412  } model;
1413 
1414  struct EXAM
1415  {
1416  gchar *text;
1417  Char_Distribution dist;
1418  } exam;
1419 
1420  GtkWidget *wg;
1421  GtkTextBuffer *buf;
1422  GtkTextIter start;
1423  GtkTextIter end;
1424 
1425  /* Get model text
1426  */
1427  tmp_code = main_preferences_get_string ("interface", "language");
1428  tmp_name = g_strconcat (main_path_data (), G_DIR_SEPARATOR_S, tmp_code, ".paragraphs", NULL);
1429  g_free (tmp_code);
1430  if (!g_file_get_contents (tmp_name, &model.text, NULL, NULL))
1431  {
1432  g_free (tmp_name);
1433  tmp_name = trans_lang_get_similar_file_name (".paragraphs");
1434  if (!g_file_get_contents (tmp_name, &model.text, NULL, NULL))
1435  {
1436  g_message ("Can't read file:\n %s\n So, not logging your score.", tmp_name);
1437  g_free (tmp_name);
1438  return FALSE;
1439  }
1440  }
1441 
1442  /* Get text under examination
1443  */
1444  wg = get_wg ("text_tutor");
1445  buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (wg));
1446  gtk_text_buffer_get_bounds (buf, &start, &end);
1447  exam.text = gtk_text_buffer_get_text (buf, &start, &end, FALSE);
1448 
1449  /* Get char distributions
1450  */
1451  tutor_char_distribution_count (model.text, &model.dist);
1452  tutor_char_distribution_count (exam.text, &exam.dist);
1453 
1454  /* Compare both distributions
1455  */
1456  deceiveness = 0;
1457  for (i = 0; i < 9 && deceiveness < 1.0e+6; i++)
1458  {
1459  for (j = 0; j < exam.dist.size; j++)
1460  if (model.dist.ch[i].letter == exam.dist.ch[j].letter)
1461  {
1462  deceiveness +=
1463  powf ((exam.dist.ch[j].freq - model.dist.ch[i].freq), 2);
1464  break;
1465  }
1466  if (j == exam.dist.size)
1467  {
1468  deceiveness += 1.0e+7;
1469  break;
1470  }
1471  }
1472  deceiveness = sqrtf (deceiveness / 9);
1473 
1474  g_print ("Corpus file: %s\n", tmp_name);
1475  if (deceiveness < DECEIVENESS_LIMIT)
1476  g_print ("\tDeviation: %.3f. OK, it is less than %.3f.\n", deceiveness, DECEIVENESS_LIMIT);
1477  else
1478  g_print ("\tDeviation: %.3f! It should be less than %.3f.\n", deceiveness, DECEIVENESS_LIMIT);
1479 
1480  g_free (tmp_name);
1481  g_free (model.text);
1482  g_free (exam.text);
1483  return (deceiveness < DECEIVENESS_LIMIT);
1484 }
1485 
1486 /**********************************************************************
1487  * Count relative frequency of letters in text
1488  */
1489 void
1491 {
1492  gchar *pt;
1493  gunichar ch;
1494  gsize i, j;
1495 
1496  pt = text;
1497 
1498  dist->size = 0;
1499  dist->total = 0;
1500  while ((ch = g_utf8_get_char (pt)) != L'\0')
1501  {
1502  /* Only count letters
1503  */
1504  if (!g_unichar_isalpha (ch))
1505  {
1506  pt = g_utf8_next_char (pt);
1507  continue;
1508  }
1509  ch = g_unichar_tolower (ch);
1510 
1511  /* Verify if ch was already counted
1512  */
1513  for (i = 0; i < dist->size; i++)
1514  {
1515  if (ch == dist->ch[i].letter)
1516  {
1517  dist->ch[i].count++;
1518  dist->total++;
1519  break;
1520  }
1521  }
1522 
1523  /* If ch was not counted yet, start to do it
1524  */
1525  if (i == dist->size && i < MAX_ALPHABET_LEN)
1526  {
1527  dist->ch[dist->size].letter = ch;
1528  dist->ch[dist->size].count = 1;
1529  dist->total++;
1530  dist->size++;
1531  }
1532 
1533  pt = g_utf8_next_char (pt);
1534  }
1535 
1536  /* Sort the list
1537  */
1538  for (i = 1; i < dist->size; i++)
1539  {
1540  gunichar aletter;
1541  guint acount;
1542 
1543  if (dist->ch[i].count > dist->ch[i - 1].count)
1544  for (j = i; j > 0; j--)
1545  {
1546  if (dist->ch[j].count <= dist->ch[j - 1].count)
1547  break;
1548 
1549  aletter = dist->ch[j - 1].letter;
1550  dist->ch[j - 1].letter = dist->ch[j].letter;
1551  dist->ch[j].letter = aletter;
1552 
1553  acount = dist->ch[j - 1].count;
1554  dist->ch[j - 1].count = dist->ch[j].count;
1555  dist->ch[j].count = acount;
1556  }
1557  }
1558 
1559  /* Write the relative frequency
1560  */
1561  for (i = 0; i < dist->size; i++)
1562  dist->ch[i].freq = ((gfloat) dist->ch[i].count) / ((gfloat) dist->ch[0].count);
1563 
1564  /*
1565  for (i = 0; i < dist->size; i++)
1566  g_message ("Char: %x, count: %u, freq:%g", dist->ch[i].letter, dist->ch[i].count, dist->ch[i].freq);
1567  g_message ("Total: %u / Size: %u ------------------------------", dist->total, dist->size);
1568  */
1569 }
1570 
1571 /**********************************************************************
1572  * Formats and draws one paragraph at the tutor window
1573  */
1574 void
1575 tutor_draw_paragraph (gchar * utf8_text)
1576 {
1577  static gchar *tmp1 = NULL;
1578  static gchar *tmp2 = NULL;
1579  gchar *ptr;
1580  GtkTextBuffer *buf;
1581 
1582  //g_free (tmp1);
1583  //g_free (tmp2);
1584 
1585  if (g_utf8_strrchr (utf8_text, -1, L'\n') == NULL)
1586  {
1587  g_message ("paragraph not terminated by carriage return: adding one.");
1588  tmp1 = g_strconcat (utf8_text, "\n", NULL);
1589  }
1590  else
1591  tmp1 = g_strdup (utf8_text);
1592 
1593  ptr = g_utf8_strrchr (tmp1, -1, L'\n');
1594  if (ptr)
1595  *ptr = '\0';
1596  else
1597  g_error ("draw_paragraph () ==> string error");
1598 
1599  tmp2 = g_strconcat (tmp1, keyb_get_utf8_paragraph_symbol (), "\n", NULL);
1600  g_free (tmp1);
1601 
1602  buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (get_wg ("text_tutor")));
1603  gtk_text_buffer_insert_at_cursor (buf, tmp2, -1);
1604  g_free (tmp2);
1605 }
1606 
1607 /**********************************************************************
1608  * Load the list of files to include in the set of "other exercises"
1609  */
1610 void
1611 tutor_load_list_other (gchar * file_name_end, GtkListStore * list)
1612 {
1613  gchar *tmp_str;
1614  gchar *dentry;
1615  GDir *dir;
1616  GtkTreeIter iter;
1617  static gchar *defstr = NULL;
1618 
1619  if (defstr == NULL)
1620  defstr = g_strdup (OTHER_DEFAULT);
1621 
1622  gtk_list_store_clear (list);
1623  gtk_list_store_append (list, &iter);
1624  gtk_list_store_set (list, &iter, 0, defstr, -1);
1625 
1626  assert_user_dir ();
1627  dir = g_dir_open (main_path_user (), 0, NULL);
1628  while ((dentry = g_strdup (g_dir_read_name (dir))) != NULL)
1629  {
1630  if (strlen (dentry) < 5)
1631  {
1632  g_free (dentry);
1633  continue;
1634  }
1635  if (!(tmp_str = strrchr (dentry, '.')))
1636  {
1637  g_free (dentry);
1638  continue;
1639  }
1640  if (! g_str_equal (file_name_end, tmp_str))
1641  {
1642  g_free (dentry);
1643  continue;
1644  }
1645 
1646  *(strrchr (dentry, '.')) = '\0';
1647  gtk_list_store_append (list, &iter);
1648  gtk_list_store_set (list, &iter, 0, dentry, -1);
1649  g_free (dentry);
1650  }
1651  g_dir_close (dir);
1652 
1653  gtk_widget_set_sensitive (get_wg ("button_other_remove"), FALSE);
1654  gtk_widget_set_sensitive (get_wg ("label_other_rename"), FALSE);
1655  gtk_widget_set_sensitive (get_wg ("entry_other_rename"), FALSE);
1656  gtk_widget_set_sensitive (get_wg ("button_other_apply"), FALSE);
1657 }
1658 
1659 void
1660 tutor_other_rename (const gchar *new_tx, const gchar *old_tx)
1661 {
1662  if (! g_str_equal (new_tx, old_tx) &&
1663  ! g_str_equal (new_tx, OTHER_DEFAULT) &&
1664  ! g_str_equal (new_tx, "") &&
1665  g_strrstr (old_tx, "*") == NULL )
1666  {
1667  gchar *old_name;
1668  gchar *new_name;
1669  gchar *old_file;
1670  gchar *new_file;
1671 
1672  if (tutor.type == TT_VELO)
1673  {
1674  old_name = g_strconcat (old_tx, ".words", NULL);
1675  new_name = g_strconcat (new_tx, ".words", NULL);
1676  }
1677  else
1678  {
1679  old_name = g_strconcat (old_tx, ".paragraphs", NULL);
1680  new_name = g_strconcat (new_tx, ".paragraphs", NULL);
1681  }
1682  old_file = g_build_filename (main_path_user (), old_name, NULL);
1683  new_file = g_build_filename (main_path_user (), new_name, NULL);
1684 
1685  if (g_file_test (new_file, G_FILE_TEST_IS_REGULAR))
1686  {
1687  g_message ("File already exists, not renaming.\n\t%s\n", new_file);
1688  gdk_display_beep (gdk_display_get_default ());
1689  }
1690  else
1691  {
1692  g_printf ("Renaming from:\n\t%s\nTo:\n\t%s\n", old_file, new_file);
1693  if (g_rename (old_file, new_file))
1694  {
1695  g_printf ("Fail: %s\n", strerror (errno));
1696  }
1697  else
1698  g_printf ("Success!\n");
1699  }
1700  g_free (old_name);
1701  g_free (new_name);
1702  g_free (old_file);
1703  g_free (new_file);
1704  }
1705 }
1706 
1707 /**********************************************************************
1708  * Put 'mesg' in the message entry line of the shared tutor window
1709  */
1710 void
1711 tutor_message (gchar * mesg)
1712 {
1713  gint pos = 0;
1714  GtkWidget *wg;
1715 
1716  if (mesg == NULL)
1717  {
1718  g_message ("tutor_message() --> not showing NULL message!");
1719  return;
1720  }
1721 
1722  wg = get_wg ("entry_mesg");
1723  callbacks_shield_set (TRUE);
1724  gtk_editable_delete_text (GTK_EDITABLE (wg), 0, -1);
1725  gtk_editable_insert_text (GTK_EDITABLE (wg), g_strdup (mesg), strlen (mesg), &pos);
1726  gtk_editable_set_position (GTK_EDITABLE (wg), -1);
1727  callbacks_shield_set (FALSE);
1728 }
1729 
1730 /**********************************************************************
1731  * Beeps (or not) at the user, in the tutor window
1732  */
1733 void
1735 {
1736  if (main_preferences_get_boolean ("tutor", "tutor_beep"))
1737  gdk_display_beep (gdk_display_get_default ());
1738 }
1739 
1740 /**********************************************************************
1741  * Speak some phrase
1742  */
1743 void
1744 tutor_speak_string (gchar *string, gboolean wait)
1745 {
1746  gchar *tmp_code;
1747  gchar *command;
1748  static gboolean espeak_OK = TRUE;
1749  static GtkWidget *wg = NULL;
1750 
1751  if (wg == NULL)
1752  wg = get_wg ("checkbutton_speech");
1753 
1754  if (espeak_OK == FALSE)
1755  return;
1756  if (!gtk_widget_get_visible (wg) )
1757  return;
1758  if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wg)) )
1759  return;
1760 
1761  /* Translators: your language code (first 2 letters of your po-file)*/
1762  tmp_code = g_strdup (_("en"));
1763  tmp_code[2] = '\0';
1764  if (wait)
1765  {
1766  command = g_strdup_printf ("espeak -v%s -k1 \"%s\"", tmp_code, string);
1767 #ifdef G_OS_UNIX
1768  espeak_OK = g_spawn_command_line_sync (command, NULL, NULL, NULL, NULL);
1769 #else
1770  espeak_OK = ! system (command);
1771 #endif
1772  }
1773  else
1774  {
1775 #ifdef G_OS_UNIX
1776  if (g_utf8_strlen (string, -1) == 1 || tutor.type == TT_VELO)
1777  command = g_strdup_printf ("espeak -v%s -k1 --punct '%s'", tmp_code, string);
1778  else
1779  command = g_strdup_printf ("espeak -v%s -k1 \"%s\"", tmp_code, string);
1780  espeak_OK = g_spawn_command_line_async (command, NULL);
1781 #else
1782  if (g_utf8_strlen (string, -1) == 1 || tutor.type == TT_VELO)
1783  command = g_strdup_printf ("espeak -v%s -k1 --punct \"%s\"", tmp_code, string);
1784  else
1785  command = g_strdup_printf ("espeak -v%s -k1 \"%s\"", tmp_code, string);
1786  espeak_OK = ! system (command);
1787 #endif
1788  }
1789  if (espeak_OK == FALSE)
1790  g_message ("Espeak not installed, so we'll say nothing:\n %s", command);
1791  g_free (tmp_code);
1792  g_free (command);
1793 }
1794 
1795 /**********************************************************************
1796  * Control delayed tips for the finger to be used
1797  */
1798 gboolean
1800 {
1801  gchar *finger;
1802  gunichar *uch = (gunichar*) unich;
1803  static gint counter = 0;
1804 
1805  if (unich == NULL)
1806  {
1807  counter++;
1808  return FALSE;
1809  }
1810  counter--;
1811 
1812  if (counter > 0)
1813  return FALSE;
1814 
1815  finger = hints_finger_name_from_char (*uch);
1816  tutor_speak_string (finger, TRUE);
1817  g_free (finger);
1818 
1819  return FALSE;
1820 }
1821 
1822 /**********************************************************************
1823  * Speak the current character to be typed
1824  */
1825 void
1827 {
1828  gchar ut8[100];
1829  static gunichar uch;
1830 
1831  if (tutor.type == TT_BASIC)
1832  {
1833  g_timeout_add (3000, (GSourceFunc) tutor_delayed_finger_tip, (gpointer) &uch);
1834  tutor_delayed_finger_tip (NULL);
1835  }
1836 
1837  uch = cursor_get_char ();
1838  switch (uch)
1839  {
1840  case L' ':
1841  strcpy (ut8, _("space"));
1842  break;
1843  case L'y':
1844  case L'Y':
1845  /* Translators: the name of letter Y */
1846  strcpy (ut8, _("wye"));
1847  break;
1848  case UPSYM:
1849  /* Translators: the name of the Return key */
1850  strcpy (ut8, _("enter"));
1851  break;
1852  case L'%':
1853  strcpy (ut8, "%");
1854  break;
1855  case L'\'':
1856  strcpy (ut8, _("apostrophe"));
1857  break;
1858  case L'\"':
1859  /* Translators: double quote symbol: " */
1860  strcpy (ut8, _("quote"));
1861  break;
1862  case L'&':
1863  /* Translators: ampersand symbol: & */
1864  strcpy (ut8, _("ampersand"));
1865  break;
1866  default:
1867  ut8[g_unichar_to_utf8 (uch, ut8)] = '\0';
1868  }
1869 
1870  tutor_speak_string (ut8, FALSE);
1871 
1872 }
1873 
1874 /**********************************************************************
1875  * Speak the next word to be typed
1876  */
1877 void
1879 {
1880  gunichar uch[100];
1881  gchar *ut8;
1882  gint i;
1883 
1884  if (cursor_advance (-1) != -1)
1885  uch[0] = L' ';
1886  else
1887  {
1888  uch[0] = cursor_get_char ();
1889  cursor_advance (1);
1890  }
1891  if (uch[0] == L' ' || uch[0] == UPSYM || uch[0] == L'\n' || uch[0] == L'\r')
1892  {
1893  for (i = 0; i < 100; i++)
1894  {
1895  uch[i] = cursor_get_char ();
1896  if (uch[i] == L' ' || uch[i] == UPSYM || uch[i] == L'\n' || uch[i] == L'\r')
1897  break;
1898  cursor_advance (1);
1899  }
1900  cursor_advance (-i);
1901  }
1902  else
1903  return;
1904 
1905  ut8 = g_ucs4_to_utf8 (uch, i, NULL, NULL, NULL);
1906  if (ut8)
1907  tutor_speak_string (ut8, FALSE);
1908  g_free (ut8);
1909 }
void accur_sort()
Definition: accuracy.c:533
void accur_wrong(gunichar uchr)
Definition: accuracy.c:329
void accur_correct(gunichar uchr, double touch_time)
Definition: accuracy.c:265
void adapt_comment(gdouble accuracy)
Definition: adaptability.c:239
void adapt_draw_random_pattern()
Definition: adaptability.c:39
void set_wg_bg_color(GtkWidget *widget, gchar *bg_color)
Definition: auxiliar.c:62
GtkWidget * get_wg(gchar *name)
Definition: auxiliar.c:40
void assert_user_dir()
Definition: auxiliar.c:101
GtkWindow * get_win(gchar *name)
Definition: auxiliar.c:50
#define _(String)
Definition: auxiliar.h:45
#define dngettext(Domain, Message, Message2, N)
Definition: auxiliar.h:42
void basic_set_lesson_increased(gboolean state)
Definition: basic.c:76
void basic_set_lesson(gint lesson)
Definition: basic.c:54
gint basic_init_char_set()
Definition: basic.c:102
gint basic_get_lesson()
Definition: basic.c:48
gunichar * basic_get_char_set()
Definition: basic.c:64
void basic_init()
Definition: basic.c:85
void basic_draw_lesson()
Definition: basic.c:257
void basic_comment(gdouble accuracy)
Definition: basic.c:356
#define MAX_BASIC_LESSONS
Definition: basic.h:18
void callbacks_shield_set(gboolean state)
Definition: callbacks.c:57
void cursor_set_blink(gboolean status)
Definition: cursor.c:43
gunichar cursor_get_char()
Definition: cursor.c:131
gboolean cursor_off(gpointer data)
Definition: cursor.c:195
gboolean cursor_on(gpointer data)
Definition: cursor.c:167
void cursor_paint_char(gchar *color_tag_name)
Definition: cursor.c:110
gint cursor_advance(gint n)
Definition: cursor.c:52
void fluid_init()
Definition: fluidness.c:135
gchar * fluid_get_paragraph_name()
Definition: fluidness.c:52
void fluid_comment(gdouble accuracy, gdouble velocity, gdouble fluidness)
Definition: fluidness.c:531
void fluid_draw_random_paragraphs()
Definition: fluidness.c:253
gchar * hints_finger_name_from_char(gunichar uch)
Definition: keyboard.c:1987
guint i
Definition: keyboard.c:55
gchar * keyb_get_name()
Definition: keyboard.c:204
gchar * keyb_get_utf8_paragraph_symbol()
Definition: keyboard.c:1649
guint j
Definition: keyboard.c:56
void hints_update_from_char(gunichar character)
Definition: keyboard.c:1911
gchar * keyb_get_country_code(const gchar *kbd)
Definition: keyboard.c:740
struct @4::@6 pos
#define UPSYM
Definition: keyboard.h:23
gboolean main_velo_txt()
Definition: main.c:91
gchar * main_preferences_get_string(gchar *group, gchar *key)
Definition: main.c:109
gchar * main_path_user()
Definition: main.c:61
gboolean main_preferences_exist(gchar *group, gchar *key)
Definition: main.c:97
gboolean main_altcolor_get_boolean(gchar *group, gchar *key)
Definition: main.c:158
gchar * main_altcolor_get_string(gchar *group, gchar *key)
Definition: main.c:151
gchar * main_path_stats()
Definition: main.c:67
gboolean main_preferences_get_boolean(gchar *group, gchar *key)
Definition: main.c:133
gchar * main_path_data()
Definition: main.c:73
#define UNIX_OK
Definition: main.h:26
#define LOCAL
Definition: main.h:38
#define GLOBAL
Definition: main.h:39
guint total
Definition: tutor.h:63
struct CHAR_DISTRIBUTION::CHARS ch[50]
guint size
Definition: tutor.h:62
gfloat velo
Definition: top10.h:46
gfloat score
Definition: top10.h:48
gint32 nchars
Definition: top10.h:44
gfloat fluid
Definition: top10.h:47
time_t when
Definition: top10.h:43
gfloat accur
Definition: top10.h:45
gint32 name_len
Definition: top10.h:49
gchar genv
Definition: top10.h:42
gchar name[255+1]
Definition: top10.h:50
gchar lang[2]
Definition: top10.h:41
gfloat top10_calc_score(Statistics *stat)
Definition: top10.c:261
void top10_read_stats(gboolean locally, gint lang)
Definition: top10.c:551
gboolean top10_compare_insert_stat(Statistics *stat, gboolean locally)
Definition: top10.c:199
gboolean top10_validate_stat(Statistics *stat)
Definition: top10.c:270
gboolean top10_global_publish(gpointer data)
Definition: top10.c:884
void top10_show_stats(gboolean locally)
Definition: top10.c:690
void top10_write_stats(gboolean locally, gint lang)
Definition: top10.c:623
#define MIN_CHARS_TO_LOG
Definition: top10.h:23
#define MAX_NAME_LEN
Definition: top10.h:38
gchar * trans_get_current_language()
Definition: translation.c:471
gchar * trans_read_text(const gchar *file_end)
Definition: translation.c:604
gchar * trans_lang_get_similar_file_name(const gchar *file_end)
Definition: translation.c:570
gboolean tutor_is_tibetan()
Definition: tutor.c:121
struct @13 tutor
void tutor_char_distribution_count(gchar *text, Char_Distribution *dist)
Definition: tutor.c:1490
gboolean tutor_eval_forward_backward(gunichar user_chr)
Definition: tutor.c:850
GTimer * tmr
Definition: tutor.c:53
void tutor_calc_stats()
Definition: tutor.c:976
void tutor_speak_word()
Definition: tutor.c:1878
void tutor_load_list_other(gchar *file_name_end, GtkListStore *list)
Definition: tutor.c:1611
double fluidity
Definition: tutor.c:95
gint tutor_get_correcting()
Definition: tutor.c:152
gchar * OTHER_DEFAULT
Definition: main.c:43
double accuracy_learning
Definition: tutor.c:74
struct @14 goal
gdouble touch_time[4000+1]
Definition: tutor.c:55
gint n_errors
Definition: tutor.c:58
gdouble tutor_goal_fluidity()
Definition: tutor.c:266
TutorType type
Definition: tutor.c:51
gdouble tutor_goal_level(guint n)
Definition: tutor.c:279
#define LEVEL_GSET(MODULE, GOAL, DEFAULT_VAL)
Definition: tutor.c:173
void tutor_other_rename(const gchar *new_tx, const gchar *old_tx)
Definition: tutor.c:1660
void tutor_update_intro()
Definition: tutor.c:456
gdouble elapsed_time
Definition: tutor.c:54
gboolean tutor_eval_forward(gunichar user_chr)
Definition: tutor.c:784
void tutor_update()
Definition: tutor.c:434
void tutor_init_timers()
Definition: tutor.c:160
double speed_professional
Definition: tutor.c:87
struct @14::@16 adapt
void tutor_speak_char()
Definition: tutor.c:1826
double fluidity_stumbling
Definition: tutor.c:96
double speed_jogging
Definition: tutor.c:85
gdouble tutor_goal_accuracy()
Definition: tutor.c:240
double speed
Definition: tutor.c:68
struct @14::@17 velo
double accuracy
Definition: tutor.c:67
double speed_walking
Definition: tutor.c:84
#define DECEIVENESS_LIMIT
Definition: tutor.c:1399
double speed_crawling
Definition: tutor.c:82
gboolean tutor_delayed_finger_tip(gpointer unich)
Definition: tutor.c:1799
struct @14::@15 basic
double accuracy_reaching
Definition: tutor.c:76
void tutor_update_start()
Definition: tutor.c:521
void tutor_speak_string(gchar *string, gboolean wait)
Definition: tutor.c:1744
gint correcting
Definition: tutor.c:60
TutorQuery query
Definition: tutor.c:52
guint ttidx
Definition: tutor.c:56
void tutor_init_goals()
Definition: tutor.c:182
double speed_racer
Definition: tutor.c:88
void tutor_set_query(TutorQuery query)
Definition: tutor.c:146
gdouble tutor_goal_speed()
Definition: tutor.c:253
gint retro_pos
Definition: tutor.c:59
void tutor_process_touch(gunichar user_chr)
Definition: tutor.c:631
TutorType tutor_get_type()
Definition: tutor.c:107
double speed_stepping
Definition: tutor.c:83
gint n_touchs
Definition: tutor.c:57
struct @14::@18 fluid
gchar * tutor_get_type_name()
Definition: tutor.c:113
GtkCssProvider * keyb_css
Definition: keyboard.c:41
double speed_running
Definition: tutor.c:86
#define GOAL_GSET(MODULE, GOAL, DEFAULT_VAL)
Definition: tutor.c:165
void tutor_message(gchar *mesg)
Definition: tutor.c:1711
double speed_flying
Definition: tutor.c:89
gboolean tutor_char_distribution_approved()
Definition: tutor.c:1401
double accuracy_improving
Definition: tutor.c:75
void tutor_beep()
Definition: tutor.c:1734
void tutor_draw_paragraph(gchar *utf8_text)
Definition: tutor.c:1575
TutorQuery tutor_get_query()
Definition: tutor.c:140
#define MAX_TOUCH_TICS
Definition: tutor.c:48
void tutor_init(TutorType tt_type)
Definition: tutor.c:294
#define TUTOR_CREAM
Definition: tutor.h:34
#define TUTOR_WHITE
Definition: tutor.h:35
TutorType
Definition: tutor.h:38
@ TT_VELO
Definition: tutor.h:41
@ TT_FLUID
Definition: tutor.h:42
@ TT_BASIC
Definition: tutor.h:39
@ TT_ADAPT
Definition: tutor.h:40
TutorQuery
Definition: tutor.h:46
@ QUERY_INTRO
Definition: tutor.h:47
@ QUERY_END
Definition: tutor.h:50
@ QUERY_START
Definition: tutor.h:48
@ QUERY_PROCESS_TOUCHS
Definition: tutor.h:49
#define MAX_ALPHABET_LEN
Definition: tutor.h:53
void velo_draw_random_words()
Definition: velocity.c:170
GList * list
Definition: velocity.c:39
void velo_comment(gdouble accuracy, gdouble velocity)
Definition: velocity.c:436
void velo_init()
Definition: velocity.c:69
gchar * velo_get_dict_name()
Definition: velocity.c:50