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)  

velocity.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  * Velocity exercise
20  */
21 #include <string.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <glib.h>
25 #include <glib/gstdio.h>
26 #include <gtk/gtk.h>
27 
28 #include "auxiliar.h"
29 #include "main.h"
30 #include "translation.h"
31 #include "keyboard.h"
32 #include "tutor.h"
33 #include "velocity.h"
34 
35 GList *word_list;
36 
37 struct
38 {
39  GList *list;
40  gint len;
41  gchar *name;
42 } dict;
43 
44 extern gchar *OTHER_DEFAULT;
45 
46 /*******************************************************************************
47  * Interface functions
48  */
49 gchar *
51 {
52  return (dict.name);
53 }
54 
55 void
57 {
58  g_list_free (dict.list);
59  dict.list = NULL;
60  dict.len = 0;
61  g_free (dict.name);
62  dict.name = NULL;
63 }
64 
65 /**********************************************************************
66  * Initialize the velo exercise window.
67  */
68 void
70 {
71  gchar *wl_name;
72 
73  if (dict.len != 0)
74  return;
75 
76  if (main_preferences_exist ("tutor", "word_list"))
77  {
78  wl_name = main_preferences_get_string ("tutor", "word_list");
79  velo_init_dict (wl_name);
80  g_free (wl_name);
81  }
82 
83  if (dict.len == 0)
84  velo_init_dict (NULL);
85 }
86 
87 /**********************************************************************
88  * Retrieves words from the dictionary.
89  */
90 void
91 velo_init_dict (gchar * list_name)
92 {
93  static gchar *word_buf = NULL;
94  gchar *word;
95  gchar *tmp_buf;
96  gchar *tmp_name;
97  gchar *tmp_code;
98  gchar *dict_name;
99 
100  if (list_name && !g_str_equal (list_name, OTHER_DEFAULT) )
101  {
102  main_preferences_set_string ("tutor", "word_list", list_name);
103  tmp_name = g_strconcat (main_path_user (), G_DIR_SEPARATOR_S, list_name, ".words", NULL);
104  g_message ("loading dictionary: %s.words", list_name);
105  dict_name = g_strdup (list_name);
106  }
107  else
108  {
109  main_preferences_remove ("tutor", "word_list");
110  tmp_code = main_preferences_get_string ("interface", "language");
111  tmp_name = g_strconcat (main_path_data (), G_DIR_SEPARATOR_S, tmp_code, ".words", NULL);
112  g_message ("loading dictionary: %s.words", tmp_code);
113  g_free (tmp_code);
114  dict_name = g_strdup ("Default");
115  }
116 
117  if (!g_file_test (tmp_name, G_FILE_TEST_IS_REGULAR))
118  {
119  g_free (tmp_name);
120  tmp_name = trans_lang_get_similar_file_name (".words");
121  g_message ("not found, loading from file:\n %s", tmp_name);
122  }
123 
124  if (g_file_get_contents (tmp_name, &tmp_buf, NULL, NULL))
125  {
126  velo_reset_dict ();
127  dict.name = dict_name;
128  g_free (word_buf);
129  word_buf = tmp_buf;
130  g_print ("Tens of words:\n 0");
131  while (*tmp_buf != '\0')
132  {
133  word = tmp_buf;
134  dict.list = g_list_prepend (dict.list, word);
135  dict.len++;
136  if (dict.len % 10 == 0)
137  g_print (" - %u", dict.len / 10);
138  while (*tmp_buf != '\n' && *tmp_buf != '\r' && *tmp_buf != '\0')
139  tmp_buf++;
140  if (*tmp_buf == '\0')
141  break;
142  while (*tmp_buf == '\n' || *tmp_buf == '\r')
143  {
144  *tmp_buf = '\0';
145  tmp_buf++;
146  }
147  }
148  g_print ("\n");
149  g_message ("Dictionary loaded!\n\n");
150  }
151  else
152  {
153  g_free (dict_name);
154  g_message ("could not open the file: %s", tmp_name);
155  tmp_code = main_preferences_get_string ("interface", "language");
156  if (g_str_equal (tmp_code, "C"))
157  g_error ("something wrong, we must quit!");
158  main_preferences_set_string ("interface", "language", "C");
159  velo_init_dict (list_name);
160  main_preferences_set_string ("interface", "language", tmp_code);
161  g_free (tmp_code);
162  }
163  g_free (tmp_name);
164 }
165 
166 /**********************************************************************
167  * Draw random phrases with words selected from a 'discretionary'
168  */
169 void
171 {
172  gint i, j;
173  gchar *word;
174  struct PARAGRAPH
175  {
176  gchar *text;
177  gsize size;
178  gsize i;
179  } par;
180 
181  par.size = 1024;
182  par.text = g_new (gchar, par.size);
183  for (i = 0; i < 4; i++) /* 4 paragraphs per exercise */
184  {
185  par.i = 0;
186  for (j = 0; j < 20; j++) /* 20 words per paragraph */
187  {
188  word = g_strdup (g_list_nth_data (dict.list, rand () % dict.len));
189  if (j == 0) /* first word, change to upercase */
190  word[0] = g_ascii_toupper (word[0]);
191 
192  if (par.i + strlen (word) + 8 > par.size) /* check for buffer sizing, some spare for paragraph ending */
193  {
194  par.size += 1024;
195  par.text = g_renew (gchar, par.text, par.size);
196  }
197 
198  strcpy (par.text + par.i, word);
199  par.i += strlen (word);
200  if (tutor_is_tibetan ())
201  {
202  /* Append a bo word delimiter */
203  strcat(par.text, "་");
204  par.i += 3;
205  }
206  else
207  {
208  par.text[par.i++] = ' ';
209  }
210  g_free (word);
211  }
212  if (tutor_is_tibetan())
213  {
214  /* Replacing the last bo word delimiter with bo stop */
215  par.i -= 3;
216  strcpy(par.text + par.i, "།");
217  par.i += 3;
218  }
219  else
220  {
221  par.i--; /* For replacing the last space with stop below */
222  }
223 
225  par.text[par.i++] = '.';
226  par.text[par.i++] = '\n';
227  par.text[par.i++] = '\0';
228  tutor_draw_paragraph (par.text);
229  }
230  g_free (par.text);
231 }
232 
233 /**********************************************************************
234  * Takes text and make a list of words, one per line, validating as UTF-8
235  */
236 gchar *
237 velo_filter_utf8 (gchar * text)
238 {
239  gunichar uch;
240  gboolean is_searching_word;
241  struct INPUT_TEXT
242  {
243  gchar *pt;
244  gulong len;
245  guint nwords;
246  } raw;
247  struct FILTERED_TEXT
248  {
249  gchar *txt;
250  gulong i;
251  gulong len;
252  } flt;
253 
254  raw.len = strlen (text);
255 
256  /* Verify empty string
257  */
258  if (raw.len == 0)
259  {
260  flt.txt = g_strdup ("01234\n56789\n43210\n98765\n:-)\n");
261  return (flt.txt);
262  }
263 
264  /* Allocate memory space for the result
265  */
266  flt.i = 0;
267  flt.len = raw.len + 1024;
268  flt.txt = g_malloc (flt.len);
269 
270  raw.pt = text;
271 
272  /* Filter
273  */
274  raw.nwords = 0;
275  is_searching_word = TRUE;
276  while (raw.pt && raw.nwords < MAX_WORDS)
277  {
278  if (*raw.pt == '\0')
279  break;
280 
281  /* Read valid utf8 char
282  */
283  if ((uch = g_utf8_get_char_validated (raw.pt, -1)) == (gunichar) - 1
284  || uch == (gunichar) - 2)
285  uch = L' ';
286 
287  /* Increase the pointer for the input text
288  */
289  raw.pt = g_utf8_find_next_char (raw.pt, NULL);
290 
291  /* Verify memory space of output buffer
292  */
293  if (flt.i < flt.len - 8)
294  {
295  flt.len += 1024;
296  flt.txt = g_realloc (flt.txt, flt.len);
297  }
298 
299  /* Test alphabetic char to form a word
300  */
301  if (g_unichar_isalpha (uch) || g_unichar_ismark (uch))
302  {
303  flt.i += g_unichar_to_utf8 (uch, &flt.txt[flt.i]);
304  is_searching_word = FALSE;
305  }
306  else if (!is_searching_word)
307  {
308  raw.nwords++;
309  flt.txt[flt.i++] = '\n';
310  is_searching_word = TRUE;
311  }
312  }
313  flt.txt[flt.i++] = '\0';
314 
315  if (raw.nwords == 0)
316  {
317  g_free (flt.txt);
318  flt.txt = g_strdup ("01234\n56789\n43210\n98765\n:-)\n");
319  }
320 
321  return (flt.txt);
322 }
323 
324 /**********************************************************************
325  * Reads the text "text_raw" and write to the dictionary.
326  * If overwrite is TRUE, then besides overwriting any .words file,
327  * it loads a lesson with the new dictionary.
328  */
329 void
330 velo_text_write_to_file (gchar * text_raw, gboolean overwrite)
331 {
332  gchar *dict_path;
333  gchar *dictio_name;
334  gchar *text_filtered;
335  FILE *fh_destiny;
336 
337  dictio_name = g_strdup_printf ("(%s)", _("Pasted_or_dropped"));
338  dict_path = g_strconcat (main_path_user (), G_DIR_SEPARATOR_S, dictio_name, ".words", NULL);
339  assert_user_dir ();
340  if (!(fh_destiny = (FILE *) g_fopen (dict_path, "w")))
341  {
342  gdk_display_beep (gdk_display_get_default ());
343  g_warning ("couldn't create the file:\n <%s>", dict_path);
344  if (overwrite == FALSE)
345  {
346  g_free (dict_path);
347  g_free (dictio_name);
348  return;
349  }
350  }
351  g_free (dict_path);
352 
353  /* Filter the text
354  */
355  text_filtered = velo_filter_utf8 (text_raw);
356  fwrite (text_filtered, sizeof (gchar), strlen (text_filtered), fh_destiny);
357  fclose (fh_destiny);
358 
359  g_free (text_filtered);
360 
361  if (overwrite == TRUE)
362  {
363  velo_init_dict (dictio_name);
365  tutor_process_touch ('\0');
366  }
367  g_free (dictio_name);
368 }
369 
370 /**********************************************************************
371  * Reads the text file "file_name" and write to the dictionary.
372  * If overwrite is TRUE, then besides overwriting any .words file,
373  * it loads a lesson with the new dictionary.
374  */
375 void
376 velo_create_dict (gchar * file_name, gboolean overwrite)
377 {
378  gchar *dict_path;
379  gchar *dictio_name;
380  gchar *text_raw;
381  gchar *text_filtered;
382  FILE *fh_destiny;
383 
384  if (!file_name)
385  {
386  gdk_display_beep (gdk_display_get_default ());
387  g_warning ("velo_create_dict(): null file name as first argument.");
388  return;
389  }
390 
391  if (!g_file_get_contents (file_name, &text_raw, NULL, NULL))
392  {
393  gdk_display_beep (gdk_display_get_default ());
394  g_warning ("couldn't read the file:\n <%s>", file_name);
395  return;
396  }
397 
398  dictio_name = g_path_get_basename (file_name);
399  dict_path = g_strconcat (main_path_user (), G_DIR_SEPARATOR_S, dictio_name, ".words", NULL);
400  assert_user_dir ();
401  if (!(fh_destiny = (FILE *) g_fopen (dict_path, "w")))
402  {
403  gdk_display_beep (gdk_display_get_default ());
404  g_warning ("couldn't create the file:\n <%s>", dict_path);
405  if (overwrite == FALSE)
406  {
407  g_free (dict_path);
408  g_free (dictio_name);
409  return;
410  }
411  }
412  g_free (dict_path);
413 
414  /* Filter the text
415  */
416  text_filtered = velo_filter_utf8 (text_raw);
417  fwrite (text_filtered, sizeof (gchar), strlen (text_filtered), fh_destiny);
418  fclose (fh_destiny);
419 
420  g_free (text_raw);
421  g_free (text_filtered);
422 
423  if (overwrite == TRUE)
424  {
425  velo_init_dict (dictio_name);
427  tutor_process_touch ('\0');
428  }
429  g_free (dictio_name);
430 }
431 
432 /**********************************************************************
433  * Put on the screen the final comments
434  */
435 void
436 velo_comment (gdouble accuracy, gdouble velocity)
437 {
438  gchar *tmp_str;
439  GtkWidget *wg;
440  GtkTextBuffer *buf;
441 
442  /*
443  * Comments
444  */
445  if (accuracy < tutor_goal_accuracy ())
446  tmp_str = g_strdup (":-(\n");
447  else if (velocity < tutor_goal_level(0))
448  tmp_str = g_strdup (_(" You are just beginning.\n"
449  " Be patient, try it again every day, rest and don't worry so much:\n"
450  " persistence and practice will improve your velocity.\n"));
451  else if (velocity < tutor_goal_level(1))
452  tmp_str = g_strdup_printf (_(" Still away from the highway. You can do better...\n"
453  " Try to reach at least %.0f WPM.\n"), tutor_goal_level(1));
454  else if (velocity < tutor_goal_level(2))
455  tmp_str = g_strdup_printf (_(" You are doing well, but need to go faster.\n"
456  " And don't forget the accuracy. Try to get %.0f WPM.\n"), tutor_goal_level(2));
457  else if (velocity < tutor_goal_level(3))
458  tmp_str = g_strdup_printf (_(" Fine. Now you need to start running.\n"
459  " Can you reach %.0f WPM?\n"), tutor_goal_level(3));
460  else if (velocity < tutor_goal_speed ())
461  tmp_str = g_strdup_printf (_(" Very good. You are almost there.\n "
462  "Can you finally reach %.0f WPM?\n"), tutor_goal_speed ());
463  else if (velocity < tutor_goal_level(4))
464  tmp_str = g_strdup (_(" Excellent. For this course, that is enough.\n"
465  " Try now the fluidness exercises, OK?\n"));
466  else if (velocity < tutor_goal_level(5))
467  tmp_str = g_strdup_printf (_(" Fast! Are you a professional?\n"
468  " So, try to get %.0f WPM!\n"), tutor_goal_level(5));
469  else if (velocity < tutor_goal_level(6))
470  /* Translators: Speed Racer is a reference to a Japanese anime franchise
471  about automobile racing, also known as Mach GoGoGo. */
472  tmp_str = g_strdup_printf (_(" Ranking good, Speed Racer!"
473  " Are you afraid of reaching %.0f WPM?\n"), tutor_goal_level(6));
474  else if (velocity < tutor_goal_level(7))
475  /* Translators: feel free to change the reference to that martial art, if you find another good analogy. */
476  tmp_str = g_strdup_printf (_(" Kung-fu mastery!\n Can you fly at %.0f WPM?\n"), tutor_goal_level(7));
477  else
478  /* Translators: Dvorak here means that infamous ergonomic keyboard layout. Feel free to change the speed mastery analogy. */
479  tmp_str = g_strdup (_(" Dvorak master!\n"
480  " I have no words to express my admiration!\n"));
481 
482  wg = get_wg ("text_tutor");
483  buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (wg));
484  gtk_text_buffer_insert_at_cursor (buf, tmp_str, strlen (tmp_str));
485  g_free (tmp_str);
486 }
GtkWidget * get_wg(gchar *name)
Definition: auxiliar.c:40
void assert_user_dir()
Definition: auxiliar.c:101
#define _(String)
Definition: auxiliar.h:45
Paragraph par
Definition: fluidness.c:44
guint i
Definition: keyboard.c:55
guint j
Definition: keyboard.c:56
void main_preferences_remove(gchar *group, gchar *key)
Definition: main.c:103
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
void main_preferences_set_string(gchar *group, gchar *key, gchar *value)
Definition: main.c:115
gchar * main_path_data()
Definition: main.c:73
gboolean trans_lang_has_stopmark()
Definition: translation.c:240
gchar * trans_lang_get_similar_file_name(const gchar *file_end)
Definition: translation.c:570
gboolean tutor_is_tibetan()
Definition: tutor.c:121
gdouble tutor_goal_level(guint n)
Definition: tutor.c:279
gdouble tutor_goal_accuracy()
Definition: tutor.c:240
double accuracy
Definition: tutor.c:67
void tutor_set_query(TutorQuery query)
Definition: tutor.c:146
gdouble tutor_goal_speed()
Definition: tutor.c:253
void tutor_process_touch(gunichar user_chr)
Definition: tutor.c:631
void tutor_draw_paragraph(gchar *utf8_text)
Definition: tutor.c:1575
@ QUERY_INTRO
Definition: tutor.h:47
void velo_draw_random_words()
Definition: velocity.c:170
gchar * OTHER_DEFAULT
Definition: main.c:43
struct @19 dict
GList * list
Definition: velocity.c:39
gint len
Definition: velocity.c:40
GList * word_list
Definition: velocity.c:35
void velo_text_write_to_file(gchar *text_raw, gboolean overwrite)
Definition: velocity.c:330
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
void velo_init_dict(gchar *list_name)
Definition: velocity.c:91
gchar * name
Definition: velocity.c:41
gchar * velo_filter_utf8(gchar *text)
Definition: velocity.c:237
void velo_create_dict(gchar *file_name, gboolean overwrite)
Definition: velocity.c:376
void velo_reset_dict()
Definition: velocity.c:56
#define MAX_WORDS
Definition: velocity.h:18