"Fossies" - the Fresh Open Source Software Archive

Member "klavaro-3.13/src/fluidness.c" (18 Apr 2021, 14399 Bytes) of package /linux/privat/klavaro-3.13.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "fluidness.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.12_vs_3.13.

    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 *
   52 fluid_get_paragraph_name ()
   53 {
   54     return par.name;
   55 }
   56 
   57 void
   58 fluid_reset_paragraph ()
   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
  135 fluid_init ()
  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)
  167         fluid_init_paragraph_list (NULL);
  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
  253 fluid_draw_random_paragraphs ()
  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);
  463     tutor_set_query (QUERY_INTRO);
  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);
  520     tutor_set_query (QUERY_INTRO);
  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 }