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)  

fluidness.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  * Fluidness exercise
20  */
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.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 "callbacks.h"
31 #include "translation.h"
32 #include "keyboard.h"
33 #include "tutor.h"
34 #include "velocity.h"
35 #include "fluidness.h"
36 
37 typedef struct
38 {
39  gchar *buffer;
40  gint len;
41  gchar name[21];
42 } Paragraph;
43 
44 Paragraph par = { NULL, 0, "" };
45 
46 extern gchar *OTHER_DEFAULT;
47 
48 /*******************************************************************************
49  * Interface functions
50  */
51 gchar *
53 {
54  return par.name;
55 }
56 
57 void
59 {
60  g_free (par.buffer);
61  par.buffer = NULL;
62  par.len = 0;
63  par.name[0] = '\0';
64 }
65 
66 /*
67  * Get from the structure 'par' the paragraph defined by 'index'
68  *
69  */
70 gchar *
71 get_par (gint index)
72 {
73  gint i;
74  gint size;
75  gint stops;
76  gchar *par_1;
77  gchar *par_2;
78  gchar *par_i;
79 
80  par_1 = par.buffer;
81  par_2 = strchr (par_1, '\n') + 1;
82  if (par_2 == NULL)
83  par_2 = par_1;
84  for (i = 0; i < index && i < par.len; i++)
85  {
86  par_1 = par_2;
87  par_2 = strchr (par_1, '\n') + 1;
88  if (par_2 == NULL)
89  par_2 = par_1;
90  }
91  size = par_2 - par_1;
92  if (size < 1)
93  {
94  g_message ("internal error while picking the paragraph %i.", index);
95  par_i = g_strdup_printf ("#%i\n", index);
96  }
97  else
98  {
99  stops = 0;
100  for (i = 1; i < size; i++)
101  if (par_1[i] == ' ')
102  if (par_1[i - 1] == '.' || par_1[i - 1] == '!' || par_1[i - 1] == '?')
103  stops++;
104  par_i = g_malloc (size + stops + 10);
105  strncpy (par_i, par_1, size);
106  par_i[size] = '\0';
107  //g_message ("Paragraph %i: %i stops", index, stops);
108 
109  if (main_preferences_get_boolean ("tutor", "double_spaces"))
110  {
111  for (i = 0; i < size - 1; i++)
112  {
113  if (par_i[i + 1] == ' ' && par_i[i + 2] != ' ')
114  if (par_i[i] == '.' || par_i[i] == '!' || par_i[i] == '?')
115  {
116  memmove (par_i + i + 3, par_i + i + 2, size - i - 1);
117  par_i[i+2] = ' ';
118  i += 2;
119  size++;
120  }
121  }
122  }
123  }
124 
125  size = strlen (par_i);
126  if (size > 0)
127  par_i[size - 1] = '\n';
128  return (par_i);
129 }
130 
131 /**********************************************************************
132  * Initialize the fluid exercise window.
133  */
134 void
136 {
137  gchar *tmp_name;
138  gchar *tmp_str;
139  FILE *fh;
140  GtkWidget *wg;
141 
142  if (!main_preferences_exist ("tutor", "fluid_paragraphs"))
143  main_preferences_set_int ("tutor", "fluid_paragraphs", 3);
144 
145  callbacks_shield_set (TRUE);
146  wg = get_wg ("spinbutton_lesson");
147  gtk_spin_button_set_value (GTK_SPIN_BUTTON (wg),
148  main_preferences_get_int ("tutor", "fluid_paragraphs"));
149  callbacks_shield_set (FALSE);
150 
151  if (par.len == 0)
152  {
153  if (main_preferences_exist ("tutor", "paragraph_list"))
154  {
155  tmp_str = main_preferences_get_string ("tutor", "paragraph_list");
156  tmp_name = g_strconcat (main_path_user (), G_DIR_SEPARATOR_S, tmp_str, ".paragraphs", NULL);
157  if ((fh = (FILE *) g_fopen (tmp_name, "r")))
158  {
159  fluid_init_paragraph_list (tmp_str);
160  fclose (fh);
161  }
162  g_free (tmp_str);
163  g_free (tmp_name);
164  }
165  }
166  if (par.len == 0)
168 }
169 
170 /**********************************************************************
171  * Reads paragraphs from the text file.
172  */
173 void
174 fluid_init_paragraph_list (gchar * list_name)
175 {
176  guint len;
177  gchar *memory_ok;
178  gchar *tmp_name;
179  gchar *tmp_code;
180  gchar str_9000[9001];
181  FILE *fh;
182 
183  if (list_name && !g_str_equal (list_name, OTHER_DEFAULT))
184  {
185  main_preferences_set_string ("tutor", "paragraph_list", list_name);
186  tmp_name = g_strconcat (main_path_user (), G_DIR_SEPARATOR_S, list_name, ".paragraphs", NULL);
187  g_message ("loading text file: %s.paragraphs", list_name);
188  strncpy (par.name, list_name, 20);
189  par.name[20] = '\0';
190  }
191  else
192  {
193  main_preferences_remove ("tutor", "paragraph_list");
194  tmp_code = main_preferences_get_string ("interface", "language");
195  tmp_name = g_strconcat (main_path_data (), G_DIR_SEPARATOR_S, tmp_code, ".paragraphs", NULL);
196  g_message ("loading text file: %s.paragraphs", tmp_code);
197  strcpy (par.name, "Default");
198  g_free (tmp_code);
199  }
200 
201  fh = (FILE *) g_fopen (tmp_name, "r");
202  if (fh == NULL && g_str_equal (par.name, "Default"))
203  fh = trans_lang_get_similar_file (".paragraphs");
204 
205  if (fh)
206  {
207  g_free (par.buffer);
208  par.buffer = g_strdup ("");
209  par.len = 0;
210  g_print ("Paragraphs:\n0");
211  while (fgets (str_9000, 9001, fh))
212  {
213  len = strlen (str_9000);
214  if (len < 2)
215  continue;
216  memory_ok = g_try_renew (gchar, par.buffer, strlen (par.buffer) + len + 2);
217  if (memory_ok)
218  par.buffer = memory_ok;
219  else
220  {
221  g_print ("\nThere was truncation: memory restrictions...");
222  break;
223  }
224  strcat (par.buffer, str_9000);
225  if (len == 9000)
226  strcat (par.buffer, "\n");
227  par.len++;
228  g_print (" - %i", par.len);
229  }
230  fclose (fh);
231  g_print ("\nText file loaded!\n\n");
232  }
233  else
234  {
235  g_message ("could not open the file: %s", tmp_name);
236  g_free (tmp_name);
237  tmp_code = main_preferences_get_string ("interface", "language");
238  if (g_str_equal (tmp_code, "C"))
239  g_error ("so, we must quit!");
240  main_preferences_set_string ("interface", "language", "C");
241  fluid_init_paragraph_list (list_name);
242  main_preferences_set_string ("interface", "language", tmp_code);
243  g_free (tmp_code);
244  return;
245  }
246  g_free (tmp_name);
247 }
248 
249 /**********************************************************************
250  * Draw random sentences selected from a '.paragraphs' file
251  */
252 void
254 {
255  gint i, j;
256  gint par_num;
257  gint rand_i[10];
258 # define FLUID_PARBUF 50
259  static gchar *text[FLUID_PARBUF] = {
260  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
261  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
262  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
263  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
264  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
265  };
266 
267  par_num = main_preferences_get_int ("tutor", "fluid_paragraphs");
268 
269  /* Use all the text, without mangling it
270  */
271  if (par_num == 0 || (main_velo_txt () && tutor_get_type () == TT_VELO))
272  {
273  par_num = par.len > FLUID_PARBUF ? FLUID_PARBUF : par.len;
274 
275  for (i = 0; i < par_num; i++)
276  g_free (text[i]);
277 
278  for (i = 0; i < par_num; i++)
279  {
280  text[i] = get_par (i);
281  tutor_draw_paragraph (text[i]);
282  }
283  return;
284  }
285 
286  /* Use some paragraphs, pseudo-randomly
287  */
288  for (i = 0; (i < par_num) && (i < par.len); i++)
289  g_free (text[i]);
290 
291  for (i = 0; (i < par_num) && (i < par.len); i++)
292  {
293  do
294  {
295  rand_i[i] = rand () % par.len;
296  for (j = 0; j < i; j++)
297  {
298  if (rand_i[i] == rand_i[j])
299  rand_i[i] = par.len;
300  }
301  }
302  while (rand_i[i] == par.len);
303 
304  text[i] = get_par (rand_i[i]);
305  tutor_draw_paragraph (text[i]);
306  }
307 }
308 
309 /**********************************************************************
310  * Takes text and validate it as UTF-8
311  */
312 gchar *
313 fluid_filter_utf8 (gchar * text)
314 {
315  gulong i;
316  gunichar uch = 0;
317  gboolean is_symbol;
318  struct INPUT_TEXT
319  {
320  gchar *pt;
321  gulong len;
322  guint npar;
323  } raw;
324  struct KEYBOARD_SYMBOLS
325  {
326  gunichar set[200];
327  guint n;
328  } sym;
329  struct FILTERED_TEXT
330  {
331  gchar *txt;
332  gulong i;
333  gulong len;
334  } flt;
335 
336  raw.len = strlen (text);
337 
338  /* Verify empty input string
339  */
340  if (raw.len == 0)
341  {
342  flt.txt = g_strdup_printf ("%i\n", rand () % 9999);
343  return (flt.txt);
344  }
345 
346  /* Allocate memory space for the result
347  */
348  flt.i = 0;
349  flt.len = raw.len + 100;
350  flt.txt = g_malloc (flt.len);
351 
352  /* By-pass BOM
353  */
354  raw.pt = text;
355  if (g_utf8_get_char_validated (raw.pt, 16) == 0xEFBBBF)
356  raw.pt = g_utf8_find_next_char (raw.pt, raw.pt + 16);
357 
358  /* Replace Win/MAC-returns
359  */
360  for (i = 0; i < raw.len; i++)
361  if (text[i] == '\r')
362  text[i] = '\n';
363 
364  /* Filter
365  */
366  sym.n = keyb_get_symbols (sym.set);
367  raw.npar = 0;
368  while (raw.pt && raw.npar < MAX_PARAGRAPHS)
369  {
370  if (*raw.pt == '\0')
371  break;
372  /* Test valid utf8 char
373  */
374  if ((uch = g_utf8_get_char_validated (raw.pt, 16)) == (gunichar) -1
375  || uch == (gunichar) -2)
376  uch = L' ';
377 
378  /* Increase the pointer for the input text
379  */
380  raw.pt = g_utf8_find_next_char (raw.pt, raw.pt + 16);
381 
382  /* Test reazonable char as valid for fluidness exercise
383  */
384  if (!(uch == L' ' || uch == L'\n' || g_unichar_isalnum (uch)))
385  {
386  is_symbol = FALSE;
387  for (i = 0; i < sym.n; i++)
388  if (uch == sym.set[i])
389  {
390  is_symbol = TRUE;
391  break;
392  }
393  if (!is_symbol)
394  uch = L' ';
395  }
396 
397  /* Verify memory space of output buffer
398  */
399  if (flt.i < flt.len - 7)
400  {
401  flt.len += 100;
402  flt.txt = g_realloc (flt.txt, flt.len);
403  }
404 
405  /* Verify new line and form the next UTF-8 char to be appended
406  */
407  if (uch == L'\n')
408  {
409  raw.npar++;
410  flt.txt[flt.i++] = '\n';
411  flt.txt[flt.i++] = '\n';
412  for (; *raw.pt == '\n' || *raw.pt == ' '; raw.pt++);
413  }
414  else
415  flt.i += g_unichar_to_utf8 (uch, &flt.txt[flt.i]);
416  }
417  if (uch != L'\n')
418  {
419  raw.npar++;
420  flt.txt[flt.i++] = '\n';
421  flt.txt[flt.i++] = '\n';
422  }
423  flt.txt[flt.i++] = '\0';
424 
425  return (flt.txt);
426 }
427 
428 /**********************************************************************
429  * Paste clipboard or dropped text in a file, so that it can be used as
430  * a customized exercise.
431  */
432 void
433 fluid_text_write_to_file (gchar * text_raw)
434 {
435  gchar *pars_path;
436  gchar *pars_name;
437  gchar *text_filtered;
438  FILE *fh_destiny;
439 
440  pars_name = g_strdup_printf ("(%s)", _("Pasted_or_dropped"));
441  pars_path = g_strconcat (main_path_user (), G_DIR_SEPARATOR_S, pars_name, ".paragraphs", NULL);
442  assert_user_dir ();
443  if (!(fh_destiny = (FILE *) g_fopen (pars_path, "w")))
444  {
445  gdk_display_beep (gdk_display_get_default ());
446  g_warning ("couldn't create the file:\n %s", pars_path);
447  g_free (pars_path);
448  g_free (pars_name);
449  return;
450  }
451  g_free (pars_path);
452 
453  /* Filter the text
454  */
455  text_filtered = fluid_filter_utf8 (text_raw);
456  fwrite (text_filtered, sizeof (gchar), strlen (text_filtered), fh_destiny);
457  fclose (fh_destiny);
458 
459  g_free (text_filtered);
460 
461  fluid_init_paragraph_list (pars_name);
462  g_free (pars_name);
464  tutor_process_touch ('\0');
465 
466  velo_text_write_to_file (text_raw, FALSE);
467 }
468 
469 /**********************************************************************
470  * Copy the file 'file_name' so that it can be used as a customized
471  * exercise.
472  */
473 void
474 fluid_copy_text_file (gchar * file_name)
475 {
476  gchar *pars_path;
477  gchar *pars_name;
478  gchar *text_raw;
479  gchar *text_filtered;
480  FILE *fh_destiny;
481 
482  if (!file_name)
483  {
484  gdk_display_beep (gdk_display_get_default ());
485  g_warning ("fluid_copy_text_file(): null file name as argument.");
486  return;
487  }
488 
489  if (!g_file_get_contents (file_name, &text_raw, NULL, NULL))
490  {
491  gdk_display_beep (gdk_display_get_default ());
492  g_warning ("couldn't read the file:\n %s\n", file_name);
493  return;
494  }
495 
496  pars_name = g_strdup (strrchr (file_name, G_DIR_SEPARATOR) + 1);
497  pars_path = g_strconcat (main_path_user (), G_DIR_SEPARATOR_S, pars_name, ".paragraphs", NULL);
498  assert_user_dir ();
499  if (!(fh_destiny = (FILE *) g_fopen (pars_path, "w")))
500  {
501  gdk_display_beep (gdk_display_get_default ());
502  g_warning ("couldn't create the file:\n %s", pars_path);
503  g_free (pars_path);
504  g_free (pars_name);
505  return;
506  }
507  g_free (pars_path);
508 
509  /* Filter the text
510  */
511  text_filtered = fluid_filter_utf8 (text_raw);
512  fwrite (text_filtered, sizeof (gchar), strlen (text_filtered), fh_destiny);
513  fclose (fh_destiny);
514 
515  g_free (text_raw);
516  g_free (text_filtered);
517 
518  fluid_init_paragraph_list (pars_name);
519  g_free (pars_name);
521  tutor_process_touch ('\0');
522 
523  velo_create_dict (file_name, FALSE);
524 }
525 
526 /**********************************************************************
527  * Put on the screen the final comments
528  */
529 #define FLUID_1 60
530 void
531 fluid_comment (gdouble accuracy, gdouble velocity, gdouble fluidness)
532 {
533  gchar *tmp_str;
534  GtkWidget *wg;
535  GtkTextBuffer *buf;
536 
537  /*
538  * Comments
539  */
540  if (accuracy < tutor_goal_accuracy ())
541  tmp_str = g_strdup (":-(\n");
542  else if (velocity < tutor_goal_speed ())
543  tmp_str = g_strdup_printf (_(" You type accurately but not so fast.\n"
544  " Can you reach %.0f WPM?\n"), tutor_goal_speed ());
545  else if (fluidness < tutor_goal_level (0))
546  tmp_str = g_strdup_printf (_(" Your rhythm is not so constant. Calm down.\n"
547  " For now, try to make the fluidness greater than %i%%.\n"), (gint) tutor_goal_level(0));
548  else if (fluidness < tutor_goal_fluidity ())
549  tmp_str = g_strdup_printf (_(" You are almost getting there. Type more fluently.\n"
550  " I want a fluidness greater than %.0f%%.\n"), tutor_goal_fluidity ());
551  else if (velocity < tutor_goal_level (1))
552  tmp_str = g_strdup (_(" Congratulations!\n"
553  " It seems to me that you are a professional.\n"
554  " You don't need this program (me) anymore.\n"
555  " Hope you have enjoyed. Thanks and be happy!\n"));
556  else
557  tmp_str = g_strdup (_(" How can you type so fast?\n"
558  " You have exceeded all my expectations.\n"
559  " Are you a machine? Could you teach me?\n"
560  " I can not help you anymore. Go to an expert!\n"));
561 
562  wg = get_wg ("text_tutor");
563  buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (wg));
564  gtk_text_buffer_insert_at_cursor (buf, tmp_str, strlen (tmp_str));
565  g_free (tmp_str);
566 }
GtkWidget * get_wg(gchar *name)
Definition: auxiliar.c:40
void assert_user_dir()
Definition: auxiliar.c:101
#define _(String)
Definition: auxiliar.h:45
void callbacks_shield_set(gboolean state)
Definition: callbacks.c:57
Paragraph par
Definition: fluidness.c:44
gchar * fluid_filter_utf8(gchar *text)
Definition: fluidness.c:313
void fluid_init()
Definition: fluidness.c:135
gchar * OTHER_DEFAULT
Definition: main.c:43
#define FLUID_PARBUF
gchar * fluid_get_paragraph_name()
Definition: fluidness.c:52
void fluid_reset_paragraph()
Definition: fluidness.c:58
void fluid_comment(gdouble accuracy, gdouble velocity, gdouble fluidness)
Definition: fluidness.c:531
gchar * get_par(gint index)
Definition: fluidness.c:71
void fluid_text_write_to_file(gchar *text_raw)
Definition: fluidness.c:433
void fluid_init_paragraph_list(gchar *list_name)
Definition: fluidness.c:174
void fluid_draw_random_paragraphs()
Definition: fluidness.c:253
void fluid_copy_text_file(gchar *file_name)
Definition: fluidness.c:474
#define MAX_PARAGRAPHS
Definition: fluidness.h:18
guint i
Definition: keyboard.c:55
guint j
Definition: keyboard.c:56
gint keyb_get_symbols(gunichar *symbols)
Definition: keyboard.c:543
gchar * name
Definition: keyboard.c:45
gboolean main_velo_txt()
Definition: main.c:91
void main_preferences_remove(gchar *group, gchar *key)
Definition: main.c:103
gint main_preferences_get_int(gchar *group, gchar *key)
Definition: main.c:121
gchar * main_preferences_get_string(gchar *group, gchar *key)
Definition: main.c:109
void main_preferences_set_int(gchar *group, gchar *key, gint value)
Definition: main.c:127
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
gboolean main_preferences_get_boolean(gchar *group, gchar *key)
Definition: main.c:133
gchar * main_path_data()
Definition: main.c:73
gint len
Definition: fluidness.c:40
gchar name[21]
Definition: fluidness.c:41
gchar * buffer
Definition: fluidness.c:39
FILE * trans_lang_get_similar_file(const gchar *file_end)
Definition: translation.c:537
gdouble tutor_goal_fluidity()
Definition: tutor.c:266
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
TutorType tutor_get_type()
Definition: tutor.c:107
void tutor_draw_paragraph(gchar *utf8_text)
Definition: tutor.c:1575
@ TT_VELO
Definition: tutor.h:41
@ QUERY_INTRO
Definition: tutor.h:47
gint len
Definition: velocity.c:40
void velo_text_write_to_file(gchar *text_raw, gboolean overwrite)
Definition: velocity.c:330
void velo_create_dict(gchar *file_name, gboolean overwrite)
Definition: velocity.c:376