eliot-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Eliot-dev] eliot dic/encoding.cpp dic/encoding.h po/eliot.... [cppdic]


From: eliot-dev
Subject: [Eliot-dev] eliot dic/encoding.cpp dic/encoding.h po/eliot.... [cppdic]
Date: Sun, 16 Dec 2007 15:58:44 +0000

CVSROOT:        /cvsroot/eliot
Module name:    eliot
Branch:         cppdic
Changes by:     Olivier Teulière <ipkiss>      07/12/16 15:58:44

Modified files:
        dic            : encoding.cpp encoding.h 
        po             : eliot.pot fr.po 
        utils          : ncurses.cpp ncurses.h 

Log message:
         - new truncString() and truncAndConvert() functions to cut a string 
while taking into account the display width
         - many improvements in the ncurses interface:
           * the box handling is now encapsulated in its own class
           * many display fixes, in particular in case of resizing
           * new panel showing the contents of the bag
           * the readString() method now also understands Left, Right, Del, 
Ctrl-U, Ctrl-K, Home, End
           * the readString() method beeps if an unrecognized key is pressed

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/eliot/dic/encoding.cpp?cvsroot=eliot&only_with_tag=cppdic&r1=1.1.2.10&r2=1.1.2.11
http://cvs.savannah.gnu.org/viewcvs/eliot/dic/encoding.h?cvsroot=eliot&only_with_tag=cppdic&r1=1.1.2.5&r2=1.1.2.6
http://cvs.savannah.gnu.org/viewcvs/eliot/po/eliot.pot?cvsroot=eliot&only_with_tag=cppdic&r1=1.6.6.4&r2=1.6.6.5
http://cvs.savannah.gnu.org/viewcvs/eliot/po/fr.po?cvsroot=eliot&only_with_tag=cppdic&r1=1.6.6.4&r2=1.6.6.5
http://cvs.savannah.gnu.org/viewcvs/eliot/utils/ncurses.cpp?cvsroot=eliot&only_with_tag=cppdic&r1=1.22.2.7&r2=1.22.2.8
http://cvs.savannah.gnu.org/viewcvs/eliot/utils/ncurses.h?cvsroot=eliot&only_with_tag=cppdic&r1=1.6.4.1&r2=1.6.4.2

Patches:
Index: dic/encoding.cpp
===================================================================
RCS file: /cvsroot/eliot/eliot/dic/Attic/encoding.cpp,v
retrieving revision 1.1.2.10
retrieving revision 1.1.2.11
diff -u -b -r1.1.2.10 -r1.1.2.11
--- dic/encoding.cpp    10 Dec 2007 11:56:39 -0000      1.1.2.10
+++ dic/encoding.cpp    16 Dec 2007 15:58:43 -0000      1.1.2.11
@@ -194,6 +194,41 @@
 }
 
 
+string truncString(const string &iStr, unsigned int iMaxWidth)
+{
+    // Heuristic: the width of a character cannot exceed the number of
+    // bytes used to represent it (even in UTF-8)
+    if (iStr.size() <= iMaxWidth)
+        return iStr;
+    return truncAndConvert(convertToWc(iStr), iMaxWidth);
+}
+
+
+string truncAndConvert(const wstring &iWstr, unsigned int iMaxWidth)
+{
+    unsigned int width = 0;
+    unsigned int pos;
+    for (pos = 0; pos < iWstr.size(); ++pos)
+    {
+        int n = wcwidth(iWstr[pos]);
+        if (n == -1)
+        {
+            ostringstream ss;
+            ss << "truncAndConvert: non printable character: " << iWstr[pos];
+            // XXX: Should we throw an exception instead? Just ignore the 
problem?
+            cerr << ss.str() << endl;;
+            //throw DicException(ss.str());
+            return convertToMb(iWstr);
+        }
+        if (width + n > iMaxWidth)
+            break;
+        width += n;
+    }
+
+    return convertToMb(iWstr.substr(0, pos));
+}
+
+
 string padAndConvert(const wstring &iWstr, unsigned int iLength,
                      bool iLeftPad, char c)
 {

Index: dic/encoding.h
===================================================================
RCS file: /cvsroot/eliot/eliot/dic/Attic/encoding.h,v
retrieving revision 1.1.2.5
retrieving revision 1.1.2.6
diff -u -b -r1.1.2.5 -r1.1.2.6
--- dic/encoding.h      10 Dec 2007 11:56:39 -0000      1.1.2.5
+++ dic/encoding.h      16 Dec 2007 15:58:43 -0000      1.1.2.6
@@ -52,6 +52,20 @@
 string convertToMb(wchar_t iWChar);
 
 /**
+ * Truncate the given string to ensure that the number of columns needed
+ * to display it is at most iMaxWidth. If the string is already less wide,
+ * it is returned without truncation
+ */
+string truncString(const string &iStr, unsigned int iMaxWidth);
+
+/**
+ * Convert the given string into a multi-byte one. If the number of columns
+ * needed to display the resulting string is more than iMaxWidth, truncate it
+ * on the right before conversion
+ */
+string truncAndConvert(const wstring &iWStr, unsigned int iMaxWidth);
+
+/**
  * Convert the given string into a multi-byte one. If the number of columns
  * needed to display the resulting string is less than iLength, pad it with
  * the given character (defaulting to space)

Index: po/eliot.pot
===================================================================
RCS file: /cvsroot/eliot/eliot/po/eliot.pot,v
retrieving revision 1.6.6.4
retrieving revision 1.6.6.5
diff -u -b -r1.6.6.4 -r1.6.6.5
--- po/eliot.pot        15 Dec 2007 20:32:34 -0000      1.6.6.4
+++ po/eliot.pot        16 Dec 2007 15:58:44 -0000      1.6.6.5
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-12-11 15:06+0100\n"
+"POT-Creation-Date: 2007-12-16 16:44+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <address@hidden>\n"
 "Language-Team: LANGUAGE <address@hidden>\n"
@@ -260,252 +260,267 @@
 msgid "result:"
 msgstr ""
 
-#: utils/ncurses.cpp:192
-msgid " Scores "
+#: utils/ncurses.cpp:271
+msgid "Scores"
 msgstr ""
 
-#: utils/ncurses.cpp:198
+#: utils/ncurses.cpp:277
 #, c-format
 msgid "Player %d: %d"
 msgstr ""
 
-#: utils/ncurses.cpp:206
-msgid " Racks "
+#: utils/ncurses.cpp:286
+msgid "Racks"
 msgstr ""
 
-#: utils/ncurses.cpp:213
+#: utils/ncurses.cpp:293
 #, c-format
 msgid "Player %d: %ls"
 msgstr ""
 
-#: utils/ncurses.cpp:224 utils/ncurses.cpp:227
+#: utils/ncurses.cpp:304 utils/ncurses.cpp:307
 msgid "Search complete"
 msgstr ""
 
-#: utils/ncurses.cpp:239
-msgid " Search results "
+#: utils/ncurses.cpp:317
+msgid "Search results"
 msgstr ""
 
-#: utils/ncurses.cpp:269
-msgid " History of the game "
+#: utils/ncurses.cpp:345
+msgid "History of the game"
 msgstr ""
 
-#: utils/ncurses.cpp:276
+#: utils/ncurses.cpp:351
 msgid " N |   RACK   |    SOLUTION     | REF | PTS | P | BONUS"
 msgstr ""
 
-#: utils/ncurses.cpp:307
-msgid " Help "
+#: utils/ncurses.cpp:385
+msgid "Help"
 msgstr ""
 
-#: utils/ncurses.cpp:312
+#: utils/ncurses.cpp:389
 msgid "[Global]"
 msgstr ""
 
-#: utils/ncurses.cpp:313
+#: utils/ncurses.cpp:390
 msgid "   h, H, ?          Show/hide help box"
 msgstr ""
 
-#: utils/ncurses.cpp:314
+#: utils/ncurses.cpp:391
 msgid "   y, Y             Show/hide history of the game"
 msgstr ""
 
-#: utils/ncurses.cpp:315
+#: utils/ncurses.cpp:392
+msgid ""
+"   b, B             Show/hide contents of the bag (including letters of the "
+"racks)"
+msgstr ""
+
+#: utils/ncurses.cpp:393
 msgid "   e, E             Show/hide dots on empty squares of the board"
 msgstr ""
 
-#: utils/ncurses.cpp:316
+#: utils/ncurses.cpp:394
 msgid "   d, D             Check the existence of a word in the dictionary"
 msgstr ""
 
-#: utils/ncurses.cpp:317
+#: utils/ncurses.cpp:395
 msgid "   j, J             Play a word"
 msgstr ""
 
-#: utils/ncurses.cpp:318
+#: utils/ncurses.cpp:396
 msgid "   s, S             Save the game"
 msgstr ""
 
-#: utils/ncurses.cpp:319
+#: utils/ncurses.cpp:397
 msgid "   l, L             Load a game"
 msgstr ""
 
-#: utils/ncurses.cpp:320
+#: utils/ncurses.cpp:398
 msgid "   q, Q             Quit"
 msgstr ""
 
-#: utils/ncurses.cpp:323
+#: utils/ncurses.cpp:401
 msgid "[Training mode]"
 msgstr ""
 
-#: utils/ncurses.cpp:324
+#: utils/ncurses.cpp:402
 msgid "   *                Take a random rack"
 msgstr ""
 
-#: utils/ncurses.cpp:325
+#: utils/ncurses.cpp:403
 msgid "   +                Complete the current rack randomly"
 msgstr ""
 
-#: utils/ncurses.cpp:326
+#: utils/ncurses.cpp:404
 msgid "   t, T             Set the rack manually"
 msgstr ""
 
-#: utils/ncurses.cpp:327
+#: utils/ncurses.cpp:405
 msgid "   c, C             Compute all the possible words"
 msgstr ""
 
-#: utils/ncurses.cpp:328
+#: utils/ncurses.cpp:406
 msgid "   r, R             Show/hide search results"
 msgstr ""
 
-#: utils/ncurses.cpp:331
+#: utils/ncurses.cpp:409
 msgid "[Duplicate mode]"
 msgstr ""
 
-#: utils/ncurses.cpp:332
+#: utils/ncurses.cpp:410
 msgid "   n, N             Switch to the next human player"
 msgstr ""
 
-#: utils/ncurses.cpp:335
+#: utils/ncurses.cpp:413
 msgid "[Free game mode]"
 msgstr ""
 
-#: utils/ncurses.cpp:336
+#: utils/ncurses.cpp:414
 msgid "   p, P             Pass your turn (with or without changing letters)"
 msgstr ""
 
-#: utils/ncurses.cpp:339
+#: utils/ncurses.cpp:417
 msgid "[Miscellaneous]"
 msgstr ""
 
-#: utils/ncurses.cpp:340
+#: utils/ncurses.cpp:418
 msgid "   <up>, <down>     Navigate in a box line by line"
 msgstr ""
 
-#: utils/ncurses.cpp:341
+#: utils/ncurses.cpp:419
 msgid "   <pgup>, <pgdown> Navigate in a box page by page"
 msgstr ""
 
-#: utils/ncurses.cpp:342
+#: utils/ncurses.cpp:420
 msgid "   Ctrl-l           Refresh the screen"
 msgstr ""
 
-#: utils/ncurses.cpp:350
-msgid " Play a word "
+#: utils/ncurses.cpp:431 wxwin/auxframes.cc:148
+msgid "Bag"
+msgstr ""
+
+#: utils/ncurses.cpp:438
+msgid " LETTER | POINTS | FREQUENCY | REMAINING"
+msgstr ""
+
+#: utils/ncurses.cpp:491
+msgid "Play a word"
 msgstr ""
 
 #. TRANSLATORS: Align the : when translating "Played word:" and
 #. "Coordinates:". For example:
 #. Pl. word   :
 #. Coordinates:
-#: utils/ncurses.cpp:351 utils/ncurses.cpp:359
+#: utils/ncurses.cpp:492 utils/ncurses.cpp:500
 msgid "Played word:"
 msgstr ""
 
-#: utils/ncurses.cpp:352 utils/ncurses.cpp:360
+#: utils/ncurses.cpp:493 utils/ncurses.cpp:501
 msgid "Coordinates:"
 msgstr ""
 
-#: utils/ncurses.cpp:374
+#: utils/ncurses.cpp:515
 msgid "Incorrect or misplaced word"
 msgstr ""
 
-#: utils/ncurses.cpp:384
-msgid " Dictionary "
+#: utils/ncurses.cpp:530
+msgid "Dictionary"
 msgstr ""
 
-#: utils/ncurses.cpp:385
+#: utils/ncurses.cpp:531
 msgid "Enter the word to check:"
 msgstr ""
 
-#: utils/ncurses.cpp:394
+#: utils/ncurses.cpp:540
 #, c-format
 msgid "The word '%ls' exists"
 msgstr ""
 
-#: utils/ncurses.cpp:396
+#: utils/ncurses.cpp:542
 #, c-format
 msgid "The word '%ls' does not exist"
 msgstr ""
 
-#: utils/ncurses.cpp:406
-msgid " Save the game "
+#: utils/ncurses.cpp:553 wxwin/mainframe.cc:464 wxwin/mainframe.cc:472
+msgid "Save the game"
 msgstr ""
 
-#: utils/ncurses.cpp:407 utils/ncurses.cpp:436
+#: utils/ncurses.cpp:554 utils/ncurses.cpp:584
 msgid "Enter the file name:"
 msgstr ""
 
-#: utils/ncurses.cpp:417
+#: utils/ncurses.cpp:564
 #, c-format
 msgid "Cannot open file %ls for writing"
 msgstr ""
 
-#: utils/ncurses.cpp:424
+#: utils/ncurses.cpp:571
 #, c-format
 msgid "Game saved in %ls"
 msgstr ""
 
-#: utils/ncurses.cpp:435
-msgid " Load a game "
+#: utils/ncurses.cpp:583 wxwin/mainframe.cc:268 wxwin/mainframe.cc:389
+#: wxwin/mainframe.cc:413
+msgid "Load a game"
 msgstr ""
 
-#: utils/ncurses.cpp:446
+#: utils/ncurses.cpp:594
 #, c-format
 msgid "Cannot open file %ls for reading"
 msgstr ""
 
-#: utils/ncurses.cpp:454
+#: utils/ncurses.cpp:602
 #, c-format
 msgid "Invalid saved game"
 msgstr ""
 
-#: utils/ncurses.cpp:458
+#: utils/ncurses.cpp:606
 #, c-format
 msgid "Game loaded"
 msgstr ""
 
-#: utils/ncurses.cpp:473
-msgid " Pass your turn "
+#: utils/ncurses.cpp:622
+msgid "Pass your turn"
 msgstr ""
 
-#: utils/ncurses.cpp:474
+#: utils/ncurses.cpp:623
 msgid "Enter the letters to change:"
 msgstr ""
 
-#: utils/ncurses.cpp:483
+#: utils/ncurses.cpp:632
 msgid "Cannot pass the turn"
 msgstr ""
 
-#: utils/ncurses.cpp:493
-msgid " Set rack "
+#: utils/ncurses.cpp:643
+msgid "Set rack"
 msgstr ""
 
-#: utils/ncurses.cpp:494
+#: utils/ncurses.cpp:644
 msgid "Enter the new letters:"
 msgstr ""
 
-#: utils/ncurses.cpp:503
+#: utils/ncurses.cpp:653
 msgid "Cannot take these letters from the bag"
 msgstr ""
 
-#: utils/ncurses.cpp:814
+#: utils/ncurses.cpp:1013
 msgid "Training mode"
 msgstr ""
 
-#: utils/ncurses.cpp:816
+#: utils/ncurses.cpp:1015
 msgid "Free game mode"
 msgstr ""
 
-#: utils/ncurses.cpp:818
+#: utils/ncurses.cpp:1017
 msgid "Duplicate mode"
 msgstr ""
 
-#: utils/ncurses.cpp:821
+#: utils/ncurses.cpp:1020
 msgid "Joker game"
 msgstr ""
 
-#: utils/ncurses.cpp:822
+#: utils/ncurses.cpp:1021
 msgid "[h for help]"
 msgstr ""
 
@@ -513,10 +528,6 @@
 msgid "Grid"
 msgstr ""
 
-#: wxwin/auxframes.cc:148
-msgid "Bag"
-msgstr ""
-
 #: wxwin/auxframes.cc:203
 msgid "Search"
 msgstr ""
@@ -770,10 +781,6 @@
 msgid "&Load...\tctrl+l"
 msgstr ""
 
-#: wxwin/mainframe.cc:268 wxwin/mainframe.cc:389 wxwin/mainframe.cc:413
-msgid "Load a game"
-msgstr ""
-
 #: wxwin/mainframe.cc:269
 msgid "&Save as...\tctrl+s"
 msgstr ""
@@ -1067,10 +1074,6 @@
 msgid "The game is empty"
 msgstr ""
 
-#: wxwin/mainframe.cc:464 wxwin/mainframe.cc:472
-msgid "Save the game"
-msgstr ""
-
 #: wxwin/mainframe.cc:471
 msgid "Cannot create "
 msgstr ""

Index: po/fr.po
===================================================================
RCS file: /cvsroot/eliot/eliot/po/fr.po,v
retrieving revision 1.6.6.4
retrieving revision 1.6.6.5
diff -u -b -r1.6.6.4 -r1.6.6.5
--- po/fr.po    15 Dec 2007 20:32:34 -0000      1.6.6.4
+++ po/fr.po    16 Dec 2007 15:58:44 -0000      1.6.6.5
@@ -8,12 +8,12 @@
 msgstr ""
 "Project-Id-Version: eliot 1.4\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-12-11 15:06+0100\n"
+"POT-Creation-Date: 2007-12-16 16:44+0100\n"
 "PO-Revision-Date: 2005-02-06 20:03+0100\n"
 "Last-Translator: Olivier Teuliere <address@hidden>\n"
 "Language-Team: French <address@hidden>\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
 
@@ -136,16 +136,15 @@
 msgid ""
 "The file containing the letters (--letters switch) must be UTF-8 encoded."
 msgstr ""
-"Le fichier contenant les lettres (option --letters) doit être encodé en "
-"UTF-8."
+"Le fichier contenant les lettres (option --letters) doit être encodé en 
UTF-"
+"8."
 
 #: dic/compdic.cpp:403
 msgid ""
 "Each line corresponds to one letter, and must contain 5 fields separated "
 "with "
 msgstr ""
-"Chaque ligne correspond à une lettre, et doit contenir 5 champs séparés "
-"par "
+"Chaque ligne correspond à une lettre, et doit contenir 5 champs séparés 
par "
 
 #: dic/compdic.cpp:404
 msgid "one or more space(s)."
@@ -277,257 +276,272 @@
 msgid "result:"
 msgstr "résultat :"
 
-#: utils/ncurses.cpp:192
-msgid " Scores "
-msgstr " Scores "
+#: utils/ncurses.cpp:271
+msgid "Scores"
+msgstr "Scores"
 
-#: utils/ncurses.cpp:198
+#: utils/ncurses.cpp:277
 #, c-format
 msgid "Player %d: %d"
 msgstr "Joueur %d : %d"
 
-#: utils/ncurses.cpp:206
-msgid " Racks "
-msgstr " Tirages "
+#: utils/ncurses.cpp:286
+msgid "Racks"
+msgstr "Tirages"
 
-#: utils/ncurses.cpp:213
+#: utils/ncurses.cpp:293
 #, c-format
 msgid "Player %d: %ls"
 msgstr "Joueur %d : %ls"
 
-#: utils/ncurses.cpp:224 utils/ncurses.cpp:227
+#: utils/ncurses.cpp:304 utils/ncurses.cpp:307
 msgid "Search complete"
 msgstr "Recherche terminée"
 
-#: utils/ncurses.cpp:239
-msgid " Search results "
-msgstr " Résultats de la recherche "
-
-#: utils/ncurses.cpp:269
-msgid " History of the game "
-msgstr " Historique de la partie "
+#: utils/ncurses.cpp:317
+msgid "Search results"
+msgstr "Résultats de la recherche"
 
-#: utils/ncurses.cpp:276
+#: utils/ncurses.cpp:345
+msgid "History of the game"
+msgstr "Historique de la partie"
+
+#: utils/ncurses.cpp:351
 msgid " N |   RACK   |    SOLUTION     | REF | PTS | P | BONUS"
 msgstr " N |  TIRAGE  |    SOLUTION     | REF | PTS | J | BONUS"
 
-#: utils/ncurses.cpp:307
-msgid " Help "
-msgstr " Aide "
+#: utils/ncurses.cpp:385
+msgid "Help"
+msgstr "Aide"
 
-#: utils/ncurses.cpp:312
+#: utils/ncurses.cpp:389
 msgid "[Global]"
 msgstr "[Général]"
 
-#: utils/ncurses.cpp:313
+#: utils/ncurses.cpp:390
 msgid "   h, H, ?          Show/hide help box"
 msgstr "   h, H, ?          Afficher/cacher la boîte d'aide"
 
-#: utils/ncurses.cpp:314
+#: utils/ncurses.cpp:391
 msgid "   y, Y             Show/hide history of the game"
 msgstr "   y, Y             Afficher/cacher l'historique de la partie"
 
-#: utils/ncurses.cpp:315
+#: utils/ncurses.cpp:392
+msgid ""
+"   b, B             Show/hide contents of the bag (including letters of the "
+"racks)"
+msgstr ""
+"   b, B             Afficher/cacher le contenu du sac (avec les lettres des "
+"tirages)"
+
+#: utils/ncurses.cpp:393
 msgid "   e, E             Show/hide dots on empty squares of the board"
 msgstr ""
 "   e, E             Afficher/cacher les points sur les cases vides du "
 "plateau de jeu"
 
-#: utils/ncurses.cpp:316
+#: utils/ncurses.cpp:394
 msgid "   d, D             Check the existence of a word in the dictionary"
-msgstr ""
-"   d, D             Vérifier l'existence d'un mot dans le dictionnaire"
+msgstr "   d, D             Vérifier l'existence d'un mot dans le 
dictionnaire"
 
-#: utils/ncurses.cpp:317
+#: utils/ncurses.cpp:395
 msgid "   j, J             Play a word"
 msgstr "   j, J             Jouer un mot"
 
-#: utils/ncurses.cpp:318
+#: utils/ncurses.cpp:396
 msgid "   s, S             Save the game"
 msgstr "   s, S             Sauvegarder la partie"
 
-#: utils/ncurses.cpp:319
+#: utils/ncurses.cpp:397
 msgid "   l, L             Load a game"
 msgstr "   l, L             Charger une partie"
 
-#: utils/ncurses.cpp:320
+#: utils/ncurses.cpp:398
 msgid "   q, Q             Quit"
 msgstr "   q, Q             Quitter"
 
-#: utils/ncurses.cpp:323
+#: utils/ncurses.cpp:401
 msgid "[Training mode]"
 msgstr "[Mode entraînement]"
 
-#: utils/ncurses.cpp:324
+#: utils/ncurses.cpp:402
 msgid "   *                Take a random rack"
 msgstr "   *                Tirage aléatoire"
 
-#: utils/ncurses.cpp:325
+#: utils/ncurses.cpp:403
 msgid "   +                Complete the current rack randomly"
-msgstr ""
-"   +                Compléter le tirage courant de manière aléatoire"
+msgstr "   +                Compléter le tirage courant de manière 
aléatoire"
 
-#: utils/ncurses.cpp:326
+#: utils/ncurses.cpp:404
 msgid "   t, T             Set the rack manually"
 msgstr "   t, T             Entrer le tirage manuellement"
 
-#: utils/ncurses.cpp:327
+#: utils/ncurses.cpp:405
 msgid "   c, C             Compute all the possible words"
 msgstr "   c, C             Calculer tous les mots possibles"
 
-#: utils/ncurses.cpp:328
+#: utils/ncurses.cpp:406
 msgid "   r, R             Show/hide search results"
 msgstr "   r, R             Afficher/cacher les résultats de la recherche"
 
-#: utils/ncurses.cpp:331
+#: utils/ncurses.cpp:409
 msgid "[Duplicate mode]"
 msgstr "[Mode duplicate]"
 
-#: utils/ncurses.cpp:332
+#: utils/ncurses.cpp:410
 msgid "   n, N             Switch to the next human player"
 msgstr "   n, N             Passer au joueur humain suivant"
 
-#: utils/ncurses.cpp:335
+#: utils/ncurses.cpp:413
 msgid "[Free game mode]"
 msgstr "[Mode partie libre]"
 
-#: utils/ncurses.cpp:336
+#: utils/ncurses.cpp:414
 msgid "   p, P             Pass your turn (with or without changing letters)"
 msgstr ""
 "   p, P             Passer son tour (en changeant ou pas certaines lettres)"
 
-#: utils/ncurses.cpp:339
+#: utils/ncurses.cpp:417
 msgid "[Miscellaneous]"
 msgstr "[Divers]"
 
-#: utils/ncurses.cpp:340
+#: utils/ncurses.cpp:418
 msgid "   <up>, <down>     Navigate in a box line by line"
 msgstr "   <haut>, <bas>    Naviguer dans une boîte ligne par ligne"
 
-#: utils/ncurses.cpp:341
+#: utils/ncurses.cpp:419
 msgid "   <pgup>, <pgdown> Navigate in a box page by page"
 msgstr "   <pgup>, <pgdown> Naviguer dans une boîte page par page"
 
-#: utils/ncurses.cpp:342
+#: utils/ncurses.cpp:420
 msgid "   Ctrl-l           Refresh the screen"
 msgstr "   Ctrl-l           Rafraîchir l'écran"
 
-#: utils/ncurses.cpp:350
-msgid " Play a word "
-msgstr " Jouer un mot "
+#: utils/ncurses.cpp:431 wxwin/auxframes.cc:148
+msgid "Bag"
+msgstr "Sac"
+
+#: utils/ncurses.cpp:438
+msgid " LETTER | POINTS | FREQUENCY | REMAINING"
+msgstr " LETTRE | POINTS | FREQUENCE | RESTANT"
+
+#: utils/ncurses.cpp:491
+msgid "Play a word"
+msgstr "Jouer un mot"
 
 #. TRANSLATORS: Align the : when translating "Played word:" and
 #. "Coordinates:". For example:
 #. Pl. word   :
 #. Coordinates:
-#: utils/ncurses.cpp:351 utils/ncurses.cpp:359
+#: utils/ncurses.cpp:492 utils/ncurses.cpp:500
 msgid "Played word:"
 msgstr "Mot joué    :"
 
-#: utils/ncurses.cpp:352 utils/ncurses.cpp:360
+#: utils/ncurses.cpp:493 utils/ncurses.cpp:501
 msgid "Coordinates:"
 msgstr "Coordonnées :"
 
-#: utils/ncurses.cpp:374
+#: utils/ncurses.cpp:515
 msgid "Incorrect or misplaced word"
 msgstr "Mot incorrect ou mal placé"
 
-#: utils/ncurses.cpp:384
-msgid " Dictionary "
-msgstr " Dictionnaire "
+#: utils/ncurses.cpp:530
+msgid "Dictionary"
+msgstr "Dictionnaire"
 
-#: utils/ncurses.cpp:385
+#: utils/ncurses.cpp:531
 msgid "Enter the word to check:"
 msgstr "Entrer le mot à vérifier:"
 
-#: utils/ncurses.cpp:394
+#: utils/ncurses.cpp:540
 #, c-format
 msgid "The word '%ls' exists"
 msgstr "Le mot '%ls' existe"
 
-#: utils/ncurses.cpp:396
+#: utils/ncurses.cpp:542
 #, c-format
 msgid "The word '%ls' does not exist"
 msgstr "Le mot '%ls' n'existe pas"
 
-#: utils/ncurses.cpp:406
-msgid " Save the game "
-msgstr " Sauvegarder la partie "
+#: utils/ncurses.cpp:553 wxwin/mainframe.cc:464 wxwin/mainframe.cc:472
+msgid "Save the game"
+msgstr "Sauvegarder la partie"
 
-#: utils/ncurses.cpp:407 utils/ncurses.cpp:436
+#: utils/ncurses.cpp:554 utils/ncurses.cpp:584
 msgid "Enter the file name:"
 msgstr "Entrer le nom du fichier :"
 
-#: utils/ncurses.cpp:417
+#: utils/ncurses.cpp:564
 #, c-format
 msgid "Cannot open file %ls for writing"
 msgstr "Impossible d'ouvrir le fichier %ls en écriture"
 
-#: utils/ncurses.cpp:424
+#: utils/ncurses.cpp:571
 #, c-format
 msgid "Game saved in %ls"
 msgstr "Partie sauvée dans %ls"
 
-#: utils/ncurses.cpp:435
-msgid " Load a game "
-msgstr " Charger une partie "
+#: utils/ncurses.cpp:583 wxwin/mainframe.cc:268 wxwin/mainframe.cc:389
+#: wxwin/mainframe.cc:413
+msgid "Load a game"
+msgstr "Charger une partie"
 
-#: utils/ncurses.cpp:446
+#: utils/ncurses.cpp:594
 #, c-format
 msgid "Cannot open file %ls for reading"
 msgstr "Impossible d'ouvrir le fichier %ls en lecture"
 
-#: utils/ncurses.cpp:454
+#: utils/ncurses.cpp:602
 #, c-format
 msgid "Invalid saved game"
 msgstr "Partie sauvée invalide"
 
-#: utils/ncurses.cpp:458
+#: utils/ncurses.cpp:606
 #, c-format
 msgid "Game loaded"
 msgstr "Partie chargée"
 
-#: utils/ncurses.cpp:473
-msgid " Pass your turn "
-msgstr " Passer son tour "
+#: utils/ncurses.cpp:622
+msgid "Pass your turn"
+msgstr "Passer son tour"
 
-#: utils/ncurses.cpp:474
+#: utils/ncurses.cpp:623
 msgid "Enter the letters to change:"
 msgstr "Entrer les lettres à changer:"
 
-#: utils/ncurses.cpp:483
+#: utils/ncurses.cpp:632
 msgid "Cannot pass the turn"
 msgstr "Impossible de passer le tour"
 
-#: utils/ncurses.cpp:493
-msgid " Set rack "
-msgstr " Choix du tirage "
+#: utils/ncurses.cpp:643
+msgid "Set rack"
+msgstr "Choix du tirage"
 
-#: utils/ncurses.cpp:494
+#: utils/ncurses.cpp:644
 msgid "Enter the new letters:"
 msgstr "Entrer les nouvelles lettres:"
 
-#: utils/ncurses.cpp:503
+#: utils/ncurses.cpp:653
 msgid "Cannot take these letters from the bag"
 msgstr "Impossible de retirer ces lettres du sac"
 
-#: utils/ncurses.cpp:814
+#: utils/ncurses.cpp:1013
 msgid "Training mode"
 msgstr "Mode entraînement"
 
-#: utils/ncurses.cpp:816
+#: utils/ncurses.cpp:1015
 msgid "Free game mode"
 msgstr "Mode partie libre"
 
-#: utils/ncurses.cpp:818
+#: utils/ncurses.cpp:1017
 msgid "Duplicate mode"
 msgstr "Mode duplicate"
 
-#: utils/ncurses.cpp:821
+#: utils/ncurses.cpp:1020
 msgid "Joker game"
 msgstr "Partie joker"
 
-#: utils/ncurses.cpp:822
+#: utils/ncurses.cpp:1021
 msgid "[h for help]"
 msgstr "[h pour l'aide]"
 
@@ -535,21 +549,17 @@
 msgid "Grid"
 msgstr "Grille"
 
-#: wxwin/auxframes.cc:148
-msgid "Bag"
-msgstr "Sac"
-
 #: wxwin/auxframes.cc:203
 msgid "Search"
 msgstr "Recherche"
 
 #: wxwin/auxframes.cc:234
 msgid "Check"
-msgstr "Vérification"
+msgstr "Vérification"
 
 #: wxwin/auxframes.cc:239
 msgid "Word to check"
-msgstr "Mot à vérifier"
+msgstr "Mot à vérifier"
 
 #: wxwin/auxframes.cc:257 wxwin/configdb.cc:203 wxwin/searchpanel.cc:107
 msgid "No dictionary"
@@ -714,11 +724,11 @@
 
 #: wxwin/confsearch.cc:36
 msgid "Search on joker in 7+1 panel"
-msgstr "Rechercher sur joker dans la fenêtre 7+1"
+msgstr "Rechercher sur joker dans la fenêtre 7+1"
 
 #: wxwin/confsearch.cc:37
 msgid "Check rack validity"
-msgstr "Vérifier la validité du tirage"
+msgstr "Vérifier la validité du tirage"
 
 #: wxwin/confsearch.cc:40
 msgid "Cancel last changes"
@@ -792,10 +802,6 @@
 msgid "&Load...\tctrl+l"
 msgstr "&Charger...\tctrl+l"
 
-#: wxwin/mainframe.cc:268 wxwin/mainframe.cc:389 wxwin/mainframe.cc:413
-msgid "Load a game"
-msgstr "Charger une partie"
-
 #: wxwin/mainframe.cc:269
 msgid "&Save as...\tctrl+s"
 msgstr "&Enregistrer sous...\tctrl+s"
@@ -1089,10 +1095,6 @@
 msgid "The game is empty"
 msgstr "La partie est vide"
 
-#: wxwin/mainframe.cc:464 wxwin/mainframe.cc:472
-msgid "Save the game"
-msgstr "Sauvegarder la partie"
-
 #: wxwin/mainframe.cc:471
 msgid "Cannot create "
 msgstr "Impossible de créer "
@@ -1194,6 +1196,18 @@
 msgid "Regular expressions"
 msgstr "Expressions régulières"
 
+#~ msgid " Racks "
+#~ msgstr " Tirages "
+
+#~ msgid " Help "
+#~ msgstr " Aide "
+
+#~ msgid " Save the game "
+#~ msgstr " Sauvegarder la partie "
+
+#~ msgid " Load a game "
+#~ msgstr " Charger une partie "
+
 #~ msgid "The rack must contain at least 2 consonants and 2 vowels\n"
 #~ msgstr "Le tirage doit contenir au moins 2 consonnes et 2 voyelles\n"
 

Index: utils/ncurses.cpp
===================================================================
RCS file: /cvsroot/eliot/eliot/utils/ncurses.cpp,v
retrieving revision 1.22.2.7
retrieving revision 1.22.2.8
diff -u -b -r1.22.2.7 -r1.22.2.8
--- utils/ncurses.cpp   15 Dec 2007 20:32:34 -0000      1.22.2.7
+++ utils/ncurses.cpp   16 Dec 2007 15:58:44 -0000      1.22.2.8
@@ -42,48 +42,126 @@
 using namespace std;
 
 
-CursesIntf::CursesIntf(WINDOW *win, Game& iGame)
-    : m_win(win), m_game(&iGame), m_state(DEFAULT), m_dying(false),
-    m_boxStart(0), m_boxLines(0), m_boxLinesData(0), m_boxY(0),
-    m_showDots(false)
+Box::Box(WINDOW *win, int y, int x, int h, int w,
+         unsigned int iHeadingLines)
+    : m_win(win),  m_x(x), m_y(y), m_w(w), m_h(h),
+    m_topLine(y + 1 + iHeadingLines),
+    m_nbLines(h - 2 - iHeadingLines), m_dataStart(0), m_dataSize(0)
 {
 }
 
 
-CursesIntf::~CursesIntf()
+void Box::draw(const string& iTitle) const
 {
-    GameFactory::Instance()->releaseGame(*m_game);
-    GameFactory::Destroy();
+    if (m_w > 3 && m_h > 2)
+    {
+        // Add one space before and after the title for readability
+        string title;
+        if (!iTitle.empty())
+            title = " " + iTitle + " ";
+        unsigned int l = title.size();
+        // Truncate the title if needed
+        if ((int)l > m_w - 2)
+            l = m_w - 2;
+
+        mvwaddch(m_win, m_y, m_x,    ACS_ULCORNER);
+        mvwhline(m_win, m_y, m_x + 1,  ACS_HLINE, (m_w - l - 2)/2);
+        mvwprintw(m_win,m_y, m_x + 1 + (m_w - l - 2)/2, "%s", title.c_str());
+        mvwhline(m_win, m_y, m_x + (m_w - l)/2 + l,
+                 ACS_HLINE, m_w - 1 - ((m_w - l)/2 + l));
+        mvwaddch(m_win, m_y, m_x + m_w - 1, ACS_URCORNER);
+
+        mvwvline(m_win, m_y + 1, m_x, ACS_VLINE, m_h - 2);
+        mvwvline(m_win, m_y + 1, m_x + m_w - 1, ACS_VLINE, m_h - 2);
+
+        mvwaddch(m_win, m_y + m_h - 1, m_x, ACS_LLCORNER);
+        mvwhline(m_win, m_y + m_h - 1, m_x + 1, ACS_HLINE, m_w - 2);
+        mvwaddch(m_win, m_y + m_h - 1, m_x + m_w - 1, ACS_LRCORNER);
+    }
 }
 
 
-void CursesIntf::drawBox(WINDOW *win, int y, int x, int h, int w,
-                         const string& iTitle)
+void Box::printDataLine(int n, int x, const char *fmt, ...) const
 {
-    if (w > 3 && h > 2)
+    if (n < getFirstLine() || n >= getLastLine() || m_w <= x - m_x + 1)
+        return;
+
+    va_list vl_args;
+    char *buf = NULL;
+    va_start(vl_args, fmt);
+    vasprintf(&buf, fmt, vl_args);
+    va_end(vl_args);
+
+    if (buf == NULL)
     {
-        int i_len = iTitle.size();
+        return;
+    }
+
+    mvwprintw(m_win, m_topLine + n - m_dataStart, x, "%s",
+              truncString(buf, m_w - 1 - x + m_x).c_str());
+    free(buf);
+}
 
-        if (i_len > w - 2) i_len = w - 2;
 
-        mvwaddch(win, y, x,    ACS_ULCORNER);
-        mvwhline(win, y, x+1,  ACS_HLINE, ( w-i_len-2)/2);
-        mvwprintw(win,y, x+1+(w-i_len-2)/2, "%s", iTitle.c_str());
-        mvwhline(win, y, x+(w-i_len)/2+i_len,
-                 ACS_HLINE, w - 1 - ((w-i_len)/2+i_len));
-        mvwaddch(win, y, x+w-1,ACS_URCORNER);
+bool Box::scrollOneLineUp()
+{
+    if (m_dataSize <= m_nbLines || m_dataStart == 0)
+        return false;
+    m_dataStart--;
+    return true;
+}
 
-        mvwvline(win, y+1, x,     ACS_VLINE, h-2);
-        mvwvline(win, y+1, x+w-1, ACS_VLINE, h-2);
 
-        mvwaddch(win, y+h-1, x,     ACS_LLCORNER);
-        mvwhline(win, y+h-1, x+1,   ACS_HLINE, w - 2);
-        mvwaddch(win, y+h-1, x+w-1, ACS_LRCORNER);
-    }
+bool Box::scrollOneLineDown()
+{
+    if (m_dataSize <= m_nbLines || m_dataStart >= m_dataSize - 1)
+        return false;
+    m_dataStart++;
+    return true;
+}
+
+
+bool Box::scrollOnePageUp()
+{
+    if (m_dataSize <= m_nbLines)
+        return false;
+    m_dataStart -= m_nbLines;
+    if (m_dataStart < 0)
+        m_dataStart = 0;
+    return true;
 }
 
 
-void CursesIntf::clearRect(WINDOW *win, int y, int x, int h, int w)
+bool Box::scrollOnePageDown()
+{
+    if (m_dataSize <= m_nbLines)
+        return false;
+    m_dataStart += m_nbLines;
+    if (m_dataStart > m_dataSize - 1)
+        m_dataStart = m_dataSize - 1;
+    return true;
+}
+
+
+bool Box::scrollBeginning()
+{
+    if (m_dataSize <= m_nbLines || m_dataStart == 0)
+        return false;
+    m_dataStart = 0;
+    return true;
+}
+
+
+bool Box::scrollEnd()
+{
+    if (m_dataSize <= m_nbLines || m_dataStart == m_dataSize - 1)
+        return false;
+    m_dataStart = m_dataSize - 1;
+    return true;
+}
+
+
+void Box::clearRect(WINDOW *win, int y, int x, int h, int w)
 {
     for (int i = 0; i < h; i++)
     {
@@ -92,32 +170,31 @@
 }
 
 
-void CursesIntf::boxPrint(WINDOW *win, int y, int x, const char *fmt, ...)
+CursesIntf::CursesIntf(WINDOW *win, Game& iGame)
+    : m_win(win), m_game(&iGame), m_state(DEFAULT), m_dying(false),
+    m_box(win, 0, 0, 0, 0), m_showDots(false)
 {
-    if (y < m_boxStart || y - m_boxStart >= m_boxLines)
-        return;
+}
 
-    va_list vl_args;
-    char *buf = NULL;
-    va_start(vl_args, fmt);
-    vasprintf(&buf, fmt, vl_args);
-    va_end(vl_args);
 
-    if (buf == NULL)
-    {
-        return;
-    }
-    mvwprintw(win, m_boxY + y - m_boxStart, x, "%s", buf);
+CursesIntf::~CursesIntf()
+{
+    GameFactory::Instance()->releaseGame(*m_game);
+    GameFactory::Destroy();
 }
 
 
-void CursesIntf::drawStatus(WINDOW *win, int y, int x,
-                            const string& iMessage, bool error)
+void CursesIntf::drawStatus(WINDOW *win, const string& iMessage, bool error)
 {
+    int cols;
+    int lines;
+    getmaxyx(win, lines, cols);
+    int x = 0;
+    int y = lines - 1;
     if (error)
         wattron(win, COLOR_PAIR(COLOR_YELLOW));
     mvwprintw(win, y, x, iMessage.c_str());
-    whline(win, ' ', COLS - x - 1 - iMessage.size());
+    whline(win, ' ', cols - x - 1 - iMessage.size());
     if (error)
         wattron(win, COLOR_PAIR(COLOR_WHITE));
 }
@@ -126,7 +203,8 @@
 void CursesIntf::drawBoard(WINDOW *win, int y, int x) const
 {
     // Box around the board
-    drawBox(win, y + 1, x + 3, 17, 47, "");
+    Box box(win, y + 1, x + 3, 17, 47);
+    box.draw();
 
     // Print the coordinates
     for (int i = 0; i < 15; i++)
@@ -189,7 +267,8 @@
 
 void CursesIntf::drawScoresRacks(WINDOW *win, int y, int x) const
 {
-    drawBox(win, y, x, m_game->getNPlayers() + 2, 25, _(" Scores "));
+    Box box(win, y, x, m_game->getNPlayers() + 2, 25);
+    box.draw(_("Scores"));
     for (int i = 0; i < m_game->getNPlayers(); i++)
     {
         if (m_game->getMode() != Game::kTRAINING && i == m_game->currPlayer())
@@ -203,7 +282,8 @@
     // Distance between the 2 boxes
     int yOff = m_game->getNPlayers() + 3;
 
-    drawBox(win, y + yOff, x, m_game->getNPlayers() + 2, 25, _(" Racks "));
+    Box box2(win, y + yOff, x, m_game->getNPlayers() + 2, 25);
+    box2.draw(_("Racks"));
     for (int i = 0; i < m_game->getNPlayers(); i++)
     {
         if (m_game->getMode() != Game::kTRAINING && i == m_game->currPlayer())
@@ -228,126 +308,187 @@
 }
 
 
-void CursesIntf::drawResults(WINDOW *win, int y, int x)
+void CursesIntf::drawResults(Box &ioBox) const
 {
     if (m_game->getMode() != Game::kTRAINING)
         return;
     Training *tr_game = static_cast<Training*>(m_game);
 
-    int h = 17;
-    int w = 25;
-    drawBox(win, y, x, h, w, _(" Search results "));
-    m_boxY = y + 1;
-    m_boxLines = h - 2;
-    m_boxLinesData = tr_game->getResults().size();
+    ioBox.draw(_("Search results"));
+    ioBox.setDataSize(tr_game->getResults().size());
 
     int i;
     const Results& res = tr_game->getResults();
-    for (i = m_boxStart; i < res.size() &&
-                         i < m_boxStart + m_boxLines; i++)
+    int x = ioBox.getLeft();
+    for (i = ioBox.getFirstLine(); i < res.size() && i < ioBox.getLastLine(); 
i++)
     {
         const Round &r = res.get(i);
         wstring coord = r.getCoord().toString();
-        boxPrint(win, i, x + 1, "%3d %s %3s",
+        ioBox.printDataLine(i, x, "%3d %s %3s",
                  r.getPoints(),
-                 padAndConvert(r.getWord(), w - 11, false).c_str(),
+                            padAndConvert(r.getWord(), ioBox.getWidth() - 9, 
false).c_str(),
                  convertToMb(coord).c_str());
     }
     // Complete the list with empty lines, to avoid trails
-    for (; i < m_boxStart + m_boxLines; i++)
+    for (; i < ioBox.getLastLine(); i++)
     {
-        boxPrint(win, i, x + 1, string(w - 2, ' ').c_str());
+        ioBox.printDataLine(i, x + 1, string(ioBox.getWidth(), ' ').c_str());
     }
 }
 
 
-void CursesIntf::drawHistory(WINDOW *win, int y, int x)
+void CursesIntf::drawHistory(Box &ioBox) const
 {
     // To allow pseudo-scrolling, without leaving trails
-    clear();
+    ioBox.clearData();
 
-    drawBox(win, y, x, LINES - y, COLS - x, _(" History of the game "));
-    m_boxY = y + 1;
-    m_boxLines = LINES - y - 2;
-    m_boxLinesData = m_game->getHistory().getSize();
+    ioBox.draw(_("History of the game"));
+    ioBox.setDataSize(m_game->getHistory().getSize());
+    int x = ioBox.getLeft();
+    int y = ioBox.getTop();
 
     // Heading
-    boxPrint(win, m_boxStart, x + 2,
-             _(" N |   RACK   |    SOLUTION     | REF | PTS | P | BONUS"));
-    mvwhline(win, y + 2, x + 2, ACS_HLINE, 55);
+    string heading = truncString(_(" N |   RACK   |    SOLUTION     | REF | 
PTS | P | BONUS"),
+                                 ioBox.getWidth() - 1);
+    mvwprintw(m_win, y, x + 1, "%s", heading.c_str());
+    mvwhline(m_win, y + 1, x + 1, ACS_HLINE, heading.size());
 
     int i;
-    for (i = m_boxStart + 0; i < m_game->getHistory().getSize() &&
-                         i < m_boxStart + m_boxLines; i++)
+    for (i = ioBox.getFirstLine();
+         i < m_game->getHistory().getSize() && i < ioBox.getLastLine(); i++)
     {
         const Turn& t = m_game->getHistory().getTurn(i);
         const Round& r = t.getRound();
         wstring coord = r.getCoord().toString();
-        boxPrint(win, i + 2, x + 2,
-                 "%2d   %s   %s   %s   %3d   %1d   %c",
+        ioBox.printDataLine(i, x,
+            " %2d   %s   %s   %s   %3d   %1d   %c",
                  i + 1, padAndConvert(t.getPlayedRack().toString(), 8).c_str(),
                  padAndConvert(r.getWord(), 15, false).c_str(),
                  padAndConvert(coord, 3).c_str(), r.getPoints(),
                  t.getPlayer(), r.getBonus() ? '*' : ' ');
     }
-    mvwvline(win, y + 1, x + 5,  ACS_VLINE, min(i + 2 - m_boxStart, 
m_boxLines));
-    mvwvline(win, y + 1, x + 16, ACS_VLINE, min(i + 2 - m_boxStart, 
m_boxLines));
-    mvwvline(win, y + 1, x + 34, ACS_VLINE, min(i + 2 - m_boxStart, 
m_boxLines));
-    mvwvline(win, y + 1, x + 40, ACS_VLINE, min(i + 2 - m_boxStart, 
m_boxLines));
-    mvwvline(win, y + 1, x + 46, ACS_VLINE, min(i + 2 - m_boxStart, 
m_boxLines));
-    mvwvline(win, y + 1, x + 50, ACS_VLINE, min(i + 2 - m_boxStart, 
m_boxLines));
+    int nbLines = min(i + 2 - ioBox.getFirstLine(),
+                      ioBox.getLastLine() - ioBox.getFirstLine() + 2);
+    mvwvline(m_win, y, x + 4,  ACS_VLINE, nbLines);
+    mvwvline(m_win, y, x + 15, ACS_VLINE, nbLines);
+    mvwvline(m_win, y, x + 33, ACS_VLINE, nbLines);
+    mvwvline(m_win, y, x + 39, ACS_VLINE, nbLines);
+    mvwvline(m_win, y, x + 45, ACS_VLINE, nbLines);
+    mvwvline(m_win, y, x + 49, ACS_VLINE, nbLines);
 }
 
 
-void CursesIntf::drawHelp(WINDOW *win, int y, int x)
+void CursesIntf::drawHelp(Box &ioBox) const
 {
     // To allow pseudo-scrolling, without leaving trails
-    clear();
-
-    drawBox(win, y, x, LINES - y, COLS - x, _(" Help "));
-    m_boxY = y + 1;
-    m_boxLines = LINES - y - 2;
+    ioBox.clearData();
+    ioBox.draw(_("Help"));
 
+    int x = ioBox.getLeft() + 1;
     int n = 0;
-    boxPrint(win, n++, x + 2, _("[Global]"));
-    boxPrint(win, n++, x + 2, _("   h, H, ?          Show/hide help box"));
-    boxPrint(win, n++, x + 2, _("   y, Y             Show/hide history of the 
game"));
-    boxPrint(win, n++, x + 2, _("   e, E             Show/hide dots on empty 
squares of the board"));
-    boxPrint(win, n++, x + 2, _("   d, D             Check the existence of a 
word in the dictionary"));
-    boxPrint(win, n++, x + 2, _("   j, J             Play a word"));
-    boxPrint(win, n++, x + 2, _("   s, S             Save the game"));
-    boxPrint(win, n++, x + 2, _("   l, L             Load a game"));
-    boxPrint(win, n++, x + 2, _("   q, Q             Quit"));
-    boxPrint(win, n++, x + 2, "");
-
-    boxPrint(win, n++, x + 2, _("[Training mode]"));
-    boxPrint(win, n++, x + 2, _("   *                Take a random rack"));
-    boxPrint(win, n++, x + 2, _("   +                Complete the current rack 
randomly"));
-    boxPrint(win, n++, x + 2, _("   t, T             Set the rack manually"));
-    boxPrint(win, n++, x + 2, _("   c, C             Compute all the possible 
words"));
-    boxPrint(win, n++, x + 2, _("   r, R             Show/hide search 
results"));
-    boxPrint(win, n++, x + 2, "");
-
-    boxPrint(win, n++, x + 2, _("[Duplicate mode]"));
-    boxPrint(win, n++, x + 2, _("   n, N             Switch to the next human 
player"));
-    boxPrint(win, n++, x + 2, "");
-
-    boxPrint(win, n++, x + 2, _("[Free game mode]"));
-    boxPrint(win, n++, x + 2, _("   p, P             Pass your turn (with or 
without changing letters)"));
-    boxPrint(win, n++, x + 2, "");
-
-    boxPrint(win, n++, x + 2, _("[Miscellaneous]"));
-    boxPrint(win, n++, x + 2, _("   <up>, <down>     Navigate in a box line by 
line"));
-    boxPrint(win, n++, x + 2, _("   <pgup>, <pgdown> Navigate in a box page by 
page"));
-    boxPrint(win, n++, x + 2, _("   Ctrl-l           Refresh the screen"));
+    ioBox.printDataLine(n++, x, _("[Global]"));
+    ioBox.printDataLine(n++, x, _("   h, H, ?          Show/hide help box"));
+    ioBox.printDataLine(n++, x, _("   y, Y             Show/hide history of 
the game"));
+    ioBox.printDataLine(n++, x, _("   b, B             Show/hide contents of 
the bag (including letters of the racks)"));
+    ioBox.printDataLine(n++, x, _("   e, E             Show/hide dots on empty 
squares of the board"));
+    ioBox.printDataLine(n++, x, _("   d, D             Check the existence of 
a word in the dictionary"));
+    ioBox.printDataLine(n++, x, _("   j, J             Play a word"));
+    ioBox.printDataLine(n++, x, _("   s, S             Save the game"));
+    ioBox.printDataLine(n++, x, _("   l, L             Load a game"));
+    ioBox.printDataLine(n++, x, _("   q, Q             Quit"));
+    ioBox.printDataLine(n++, x, "");
+
+    ioBox.printDataLine(n++, x, _("[Training mode]"));
+    ioBox.printDataLine(n++, x, _("   *                Take a random rack"));
+    ioBox.printDataLine(n++, x, _("   +                Complete the current 
rack randomly"));
+    ioBox.printDataLine(n++, x, _("   t, T             Set the rack 
manually"));
+    ioBox.printDataLine(n++, x, _("   c, C             Compute all the 
possible words"));
+    ioBox.printDataLine(n++, x, _("   r, R             Show/hide search 
results"));
+    ioBox.printDataLine(n++, x, "");
+
+    ioBox.printDataLine(n++, x, _("[Duplicate mode]"));
+    ioBox.printDataLine(n++, x, _("   n, N             Switch to the next 
human player"));
+    ioBox.printDataLine(n++, x, "");
+
+    ioBox.printDataLine(n++, x, _("[Free game mode]"));
+    ioBox.printDataLine(n++, x, _("   p, P             Pass your turn (with or 
without changing letters)"));
+    ioBox.printDataLine(n++, x, "");
+
+    ioBox.printDataLine(n++, x, _("[Miscellaneous]"));
+    ioBox.printDataLine(n++, x, _("   <up>, <down>     Navigate in a box line 
by line"));
+    ioBox.printDataLine(n++, x, _("   <pgup>, <pgdown> Navigate in a box page 
by page"));
+    ioBox.printDataLine(n++, x, _("   Ctrl-l           Refresh the screen"));
+
+    ioBox.setDataSize(n);
+}
+
+
+void CursesIntf::drawBag(Box &ioBox) const
+{
+    // To allow pseudo-scrolling, without leaving trails
+    ioBox.clearData();
+
+    ioBox.draw(_("Bag"));
+    vector<Tile> allTiles = m_game->getDic().getAllTiles();
+    ioBox.setDataSize(allTiles.size());
+    int x = ioBox.getLeft();
+    int y = ioBox.getTop();
+
+    // Heading
+    string heading = truncString(_(" LETTER | POINTS | FREQUENCY | REMAINING"),
+                                 ioBox.getWidth() - 1);
+    mvwprintw(m_win, y, x + 1, "%s", heading.c_str());
+    mvwhline(m_win, y + 1, x + 1, ACS_HLINE, heading.size());
+
+    int i;
+    for (i = ioBox.getFirstLine(); i < (int)allTiles.size() && i < 
ioBox.getLastLine(); i++)
+    {
+        ioBox.printDataLine(i, ioBox.getLeft() + 1,
+                            "  %s        %2d        %2d       %s",
+                            padAndConvert(wstring(1, allTiles[i].toChar()), 
2).c_str(),
+                            allTiles[i].getPoints(),
+                            allTiles[i].maxNumber(),
+                            
convertToMb(wstring(m_game->getBag().in(allTiles[i]),
+                                                
allTiles[i].toChar())).c_str());
+    }
+
+    int nbLines = min(i + 2 - ioBox.getFirstLine(),
+                      ioBox.getLastLine() - ioBox.getFirstLine() + 2);
+    mvwvline(m_win, y, x + 9,  ACS_VLINE, nbLines);
+    mvwvline(m_win, y, x + 18, ACS_VLINE, nbLines);
+    mvwvline(m_win, y, x + 30, ACS_VLINE, nbLines);
+}
+
+
+void CursesIntf::setState(State iState)
+{
+    // Clear the previous box
+    m_box.clear();
+
+    // Get the size of the screen (better than using COLS and LINES directly,
+    // according to the manual)
+    int lines;
+    int cols;
+    getmaxyx(m_win, lines, cols);
 
-    m_boxLinesData = n;
+    m_state = iState;
+    if (m_state == DEFAULT)
+        m_box = Box(m_win, 0, 0, 0, 0);
+    else if (m_state == RESULTS)
+        m_box = Box(m_win, 3, 54, 17, 25);
+    else if (m_state == HISTORY)
+        m_box = Box(m_win, 1, 0, lines - 1, cols, 2);
+    else if (m_state == HELP)
+        m_box = Box(m_win, 1, 0, lines - 1, cols);
+    else if (m_state == BAG)
+        m_box = Box(m_win, 1, 0, lines - 1, cols, 2);
 }
 
 
 void CursesIntf::playWord(WINDOW *win, int y, int x)
 {
-    drawBox(win, y, x, 4, 32, _(" Play a word "));
+    Box box(win, y, x, 4, 32);
+    box.draw(_("Play a word"));
     mvwprintw(win, y + 1, x + 2, _("Played word:"));
     mvwprintw(win, y + 2, x + 2, _("Coordinates:"));
     wrefresh(win);
@@ -371,17 +512,22 @@
         int res = m_game->play(coord, word);
         if (res)
         {
-            drawStatus(win, LINES - 1, 0, _("Incorrect or misplaced word"));
+            drawStatus(win, _("Incorrect or misplaced word"));
+        }
+        else
+        {
+            // If everything went well, go back to the default view
+            setState(DEFAULT);
         }
     }
-    m_state = DEFAULT;
-    clearRect(win, y, x, 4, 32);
+    box.clear();
 }
 
 
 void CursesIntf::checkWord(WINDOW *win, int y, int x)
 {
-    drawBox(win, y, x, 4, 32, _(" Dictionary "));
+    Box box(win, y, x, 4, 32);
+    box.draw(_("Dictionary"));
     mvwprintw(win, y + 1, x + 2, _("Enter the word to check:"));
     wrefresh(win);
 
@@ -394,16 +540,17 @@
             snprintf(s, 100, _("The word '%ls' exists"), word.c_str());
         else
             snprintf(s, 100, _("The word '%ls' does not exist"), word.c_str());
-        drawStatus(win, LINES - 1, 0, s);
+        drawStatus(win, s);
     }
     m_state = DEFAULT;
-    clearRect(win, y, x, 4, 32);
+    box.clear();
 }
 
 
 void CursesIntf::saveGame(WINDOW *win, int y, int x)
 {
-    drawBox(win, y, x, 4, 32, _(" Save the game "));
+    Box box(win, y, x, 4, 32);
+    box.draw(_("Save the game"));
     mvwprintw(win, y + 1, x + 2, _("Enter the file name:"));
     wrefresh(win);
 
@@ -423,16 +570,17 @@
             fout.close();
             snprintf(s, 100, _("Game saved in %ls"), filename.c_str());
         }
-        drawStatus(win, LINES - 1, 0, s);
+        drawStatus(win, s);
     }
     m_state = DEFAULT;
-    clearRect(win, y, x, 4, 32);
+    box.clear();
 }
 
 
 void CursesIntf::loadGame(WINDOW *win, int y, int x)
 {
-    drawBox(win, y, x, 4, 32, _(" Load a game "));
+    Box box(win, y, x, 4, 32);
+    box.draw(_("Load a game"));
     mvwprintw(win, y + 1, x + 2, _("Enter the file name:"));
     wrefresh(win);
 
@@ -461,16 +609,17 @@
             }
             fclose(fin);
         }
-        drawStatus(win, LINES - 1, 0, s);
+        drawStatus(win, s);
     }
     m_state = DEFAULT;
-    clearRect(win, y, x, 4, 32);
+    box.clear();
 }
 
 
 void CursesIntf::passTurn(WINDOW *win, int y, int x, FreeGame &iGame)
 {
-    drawBox(win, y, x, 4, 32, _(" Pass your turn "));
+    Box box(win, y, x, 4, 32);
+    box.draw(_("Pass your turn"));
     mvwprintw(win, y + 1, x + 2, _("Enter the letters to change:"));
     wrefresh(win);
 
@@ -480,17 +629,18 @@
         int res = iGame.pass(letters, m_game->currPlayer());
         if (res)
         {
-            drawStatus(win, LINES - 1, 0, _("Cannot pass the turn"));
+            drawStatus(win, _("Cannot pass the turn"));
         }
     }
     m_state = DEFAULT;
-    clearRect(win, y, x, 4, 32);
+    box.clear();
 }
 
 
 void CursesIntf::setRack(WINDOW *win, int y, int x, Training &iGame)
 {
-    drawBox(win, y, x, 4, 32, _(" Set rack "));
+    Box box(win, y, x, 4, 32);
+    box.draw(_("Set rack"));
     mvwprintw(win, y + 1, x + 2, _("Enter the new letters:"));
     wrefresh(win);
 
@@ -500,21 +650,26 @@
         int res = iGame.setRackManual(false, letters);
         if (res)
         {
-            drawStatus(win, LINES - 1, 0, _("Cannot take these letters from 
the bag"));
+            drawStatus(win, _("Cannot take these letters from the bag"));
         }
     }
     m_state = DEFAULT;
-    clearRect(win, y, x, 4, 32);
+    box.clear();
 }
 
 
 bool CursesIntf::readString(WINDOW *win, int y, int x, int n, wstring &oString,
                             unsigned int flag)
 {
+    // Save the initial position
+    int x0 = x;
     wint_t c;
     wmove(win, y, x);
     curs_set(1);
     int res;
+    // Position in the string before which to insert the next character
+    // (the character will be added at the end if pos == oString.size())
+    unsigned int pos = 0;
     while ((res = get_wch(&c)) != ERR)
     {
         if (c == 0x1b )  // Esc
@@ -529,43 +684,98 @@
         }
         else if (c == 0x0c)  // Ctrl-L
         {
-//             clear();
             redraw(win);
             wmove(win, y, x);
         }
-        else if (c == KEY_BACKSPACE && res == KEY_CODE_YES && !oString.empty())
+        else if (c == 0x0b)  // Ctrl-K
+        {
+            // Remove everything after the cursor position
+            int len = oString.size() - pos;
+            oString = oString.erase(pos);
+            mvwprintw(win, y, x, string(len, ' ').c_str());
+            wmove(win, y, x);
+        }
+        else if (c == 0x15)  // Ctrl-U
+        {
+            // Remove everything before the cursor position
+            oString.erase(0, pos);
+            int len = pos;
+            x = x0;
+            pos = 0;
+            mvwprintw(win, y, x0, "%s", convertToMb(oString + wstring(len, L' 
')).c_str());
+            wmove(win, y, x);
+        }
+        else if (res == KEY_CODE_YES)
+        {
+            if (c == KEY_BACKSPACE && pos != 0)
+            {
+                x--;
+                pos--;
+                oString.erase(pos, 1);
+                mvwprintw(win, y, x0, "%s", convertToMb(oString + L" 
").c_str());
+                wmove(win, y, x);
+            }
+            else if (c == KEY_DC)
+            {
+                oString.erase(pos, 1);
+                mvwprintw(win, y, x0, "%s", convertToMb(oString + L" 
").c_str());
+                wmove(win, y, x);
+            }
+            else if (c == KEY_LEFT && pos != 0)
         {
             x--;
-            mvwprintw(win, y, x, " ");
+                pos--;
             wmove(win, y, x);
-            oString.erase(oString.size() - 1);
         }
-        else if (res == OK && iswalnum(c) && oString.size() < (unsigned int)n)
+            else if (c == KEY_RIGHT && pos != oString.size())
         {
-            mvwprintw(win, y, x, "%lc", c);
             x++;
-            oString += c;
+                pos++;
+                wmove(win, y, x);
+            }
+            else if (c == KEY_HOME)
+            {
+                x = x0;
+                pos = 0;
+                wmove(win, y, x);
+            }
+            else if (c == KEY_END)
+            {
+                x = x0 + oString.size();
+                pos = oString.size();
+                wmove(win, y, x);
         }
         else
+                beep();
+        }
+        else if (res == OK && iswalnum(c) && oString.size() < (unsigned int)n)
         {
-            if (flag & kJOKER && c == L'?')
+            x++;
+            oString.insert(pos++, 1, c);
+            mvwprintw(win, y, x0, "%s", convertToMb(oString).c_str());
+            wmove(win, y, x);
+        }
+        else if (flag & kJOKER && c == L'?')
             {
-                mvwprintw(win, y, x, "%lc", c);
                 x++;
-                oString += c;
+            oString.insert(pos++, 1, c);
+            mvwprintw(win, y, x0, "%s", convertToMb(oString).c_str());
+            wmove(win, y, x);
             }
-            if (flag & kFILENAME)
+        else if (flag & kFILENAME)
             {
                 if (c == L'/' || c == L'.' || c == L'-' || c == L'_' || c == 
L' ')
                 {
-                    mvwprintw(win, y, x, "%lc", c);
                     x++;
                     oString += c;
+                mvwprintw(win, y, x0, "%s", convertToMb(oString).c_str());
+                wmove(win, y, x);
                 }
+            else
+                beep();
             }
-        }
-//         else
-//             mvwprintw(win, 0, 0, "%3lc", c);
+        else
+            beep();
     }
     curs_set(0);
     return false;
@@ -651,46 +861,22 @@
         if (res != 2)
             return res;
     }
-    else // m_state is in {HELP, RESULTS, HISTORY}
+    else // m_state is in {HELP, RESULTS, HISTORY, BAG}
     {
         switch (iKey)
         {
             case KEY_HOME:
-                if (m_boxLinesData <= m_boxLines && m_boxStart > 0)
-                    return 0;
-                m_boxStart = 0;
-                return 1;
+                return m_box.scrollBeginning() ? 1 : 0;
             case KEY_END:
-                if (m_boxLinesData <= m_boxLines &&
-                    m_boxStart < m_boxLinesData - 1)
-                    return 0;
-                m_boxStart = m_boxLinesData - 1;
-                return 1;
+                return m_box.scrollEnd() ? 1 : 0;
             case KEY_UP:
-                if (m_boxLinesData <= m_boxLines || m_boxStart <= 0)
-                    return 0;
-                m_boxStart--;
-                return 1;
+                return m_box.scrollOneLineUp() ? 1 : 0;
             case KEY_DOWN:
-                if (m_boxLinesData <= m_boxLines ||
-                    m_boxStart >= m_boxLinesData - 1)
-                    return 0;
-                m_boxStart++;
-                return 1;
+                return m_box.scrollOneLineDown() ? 1 : 0;
             case KEY_PPAGE:
-                if (m_boxLinesData <= m_boxLines)
-                    return 0;
-                m_boxStart -= m_boxLines;
-                if (m_boxStart < 0)
-                    m_boxStart = 0;
-                return 1;
+                return m_box.scrollOnePageUp() ? 1 : 0;
             case KEY_NPAGE:
-                if (m_boxLinesData <= m_boxLines)
-                    return 0;
-                m_boxStart += m_boxLines;
-                if (m_boxStart > m_boxLinesData - 1)
-                    m_boxStart = m_boxLinesData - 1;
-                return 1;
+                return m_box.scrollOnePageDown() ? 1 : 0;
         }
     }
 
@@ -701,10 +887,9 @@
         case 'H':
         case '?':
             if (m_state == HELP)
-                m_state = DEFAULT;
+                setState(DEFAULT);
             else
-                m_state = HELP;
-            m_boxStart = 0;
+                setState(HELP);
             clear();
             return 1;
 
@@ -712,10 +897,9 @@
         case 'y':
         case 'Y':
             if (m_state == HISTORY)
-                m_state = DEFAULT;
+                setState(DEFAULT);
             else
-                m_state = HISTORY;
-            m_boxStart = 0;
+                setState(HISTORY);
             clear();
             return 1;
 
@@ -725,11 +909,20 @@
             if (m_game->getMode() != Game::kTRAINING)
                 return 0;
             if (m_state == RESULTS)
-                m_state = DEFAULT;
+                setState(DEFAULT);
             else
-                m_state = RESULTS;
-            m_boxStart = 0;
-            clearRect(m_win, 3, 54, 30, 25);
+                setState(RESULTS);
+            Box::clearRect(m_win, 3, 54, 30, 25);
+            return 1;
+
+        // Toggle bag
+        case 'b':
+        case 'B':
+            if (m_state == BAG)
+                setState(DEFAULT);
+            else
+                setState(BAG);
+            clear();
             return 1;
 
         // Toggle dots display
@@ -749,7 +942,7 @@
         // Play a word
         case 'j':
         case 'J':
-            if (m_state != DEFAULT)
+            if (m_state != DEFAULT && m_state != RESULTS)
                 return 0;
             playWord(m_win, 22, 10);
             return 1;
@@ -757,6 +950,8 @@
         // Ctrl-L should clear and redraw the screen
         case 0x0c:
             clear();
+            // Force the re-definition of the current box
+            setState(m_state);
             return 1;
 
         case 'l':
@@ -776,7 +971,7 @@
         // Quit
         case 'q':
         case 'Q':
-        case 0x1b: // Esc
+        //case 0x1b: // Esc
             m_dying = true;
             return 0;
 
@@ -795,16 +990,20 @@
     }
     else if (m_state == RESULTS)
     {
-        drawResults(win, 3, 54);
+        drawResults(m_box);
         drawBoard(win, 2, 0);
     }
     else if (m_state == HELP)
     {
-        drawHelp(win, 1, 0);
+        drawHelp(m_box);
     }
     else if (m_state == HISTORY)
     {
-        drawHistory(win, 1, 0);
+        drawHistory(m_box);
+    }
+    else if (m_state == BAG)
+    {
+        drawBag(m_box);
     }
 
     // Title
@@ -881,7 +1080,7 @@
     // Do not echo
     noecho();
 
-    // mainIntf will take care of destroying game for us.
+    // mainIntf will take care of destroying game for us
     CursesIntf mainIntf(wBoard, *game);
     mainIntf.redraw(wBoard);
 

Index: utils/ncurses.h
===================================================================
RCS file: /cvsroot/eliot/eliot/utils/ncurses.h,v
retrieving revision 1.6.4.1
retrieving revision 1.6.4.2
diff -u -b -r1.6.4.1 -r1.6.4.2
--- utils/ncurses.h     3 Dec 2007 17:27:34 -0000       1.6.4.1
+++ utils/ncurses.h     16 Dec 2007 15:58:44 -0000      1.6.4.2
@@ -32,6 +32,69 @@
 using std::wstring;
 
 
+class Box
+{
+    public:
+        // Create a titled box with the specified position and size,
+        // containing iHeadingLines non-scrolling lines.
+        // The number of data to display (with the printLine() method)
+        // can be set later using the setDataSize() method.
+        Box(WINDOW *win, int y, int x, int h, int w,
+            unsigned int iHeadingLines = 0);
+
+        // Simply draw the box (without any content)
+        void draw(const string& iTitle = "") const;
+
+        // Print data line number n (starting at 0), taking care of
+        // the current scrolling state
+        void printDataLine(int n, int x, const char *fmt, ...) const;
+
+        // Set the number of lines of the data to display
+        void setDataSize(unsigned int iNbLines) { m_dataSize = iNbLines; }
+
+        // Control scrolling
+        // Return true if redrawing is needed, false otherwise
+        bool scrollOneLineUp();
+        bool scrollOneLineDown();
+        bool scrollOnePageUp();
+        bool scrollOnePageDown();
+        bool scrollBeginning();
+        bool scrollEnd();
+
+        // Clear the box completely
+        void clear() const { clearRect(m_win, m_y, m_x, m_h, m_w); }
+        // Clear the scrolling zone of the box
+        void clearData() const { clearRect(m_win, m_topLine, m_x + 1,
+                                           m_nbLines, getWidth()); }
+        // Clear an arbitrary rectangular zone
+        static void clearRect(WINDOW *win, int y, int x, int h, int w);
+
+        // First line of data to display (included)
+        int getFirstLine() const { return m_dataStart; }
+        // Last line of data to display (excluded)
+        int getLastLine() const { return m_dataStart + m_nbLines; }
+
+        // First line inside the box
+        int getTop() const { return m_y + 1; }
+        // First column available for writing
+        int getLeft() const { return m_x + 1; }
+        // Client width
+        int getWidth() const { return m_w - 2; }
+
+    private:
+        WINDOW *m_win;
+        int m_x;
+        int m_y;
+        int m_w;
+        int m_h;
+        string m_title;
+        int m_topLine;
+        int m_nbLines;
+        int m_dataStart;
+        int m_dataSize;
+};
+
+
 /**
  * This class implements the ncurses interface.
  */
@@ -53,28 +116,27 @@
         DEFAULT,    // Default state
         HELP,       // Help panel is shown
         HISTORY,    // Game history panel is shown
-        RESULTS     // Search results panel is shown
+        RESULTS,    // Search results panel is shown
+        BAG         // Bag contents panel is shown
     };
-    // Draw a titled box with the specified position and size
-    static void drawBox(WINDOW *win, int y, int x, int h, int w,
-                        const string& iTitle);
-    // Clear a rectangular zone
-    static void clearRect(WINDOW *win, int y, int x, int h, int w);
-    // Print a line in a box, taking care of the current offset
-    void boxPrint(WINDOW *win, int y, int x, const char *fmt, ...);
+
     // Write a message in the "status line"
-    void drawStatus(WINDOW *win, int y, int x,
-                    const string& iMessage, bool error = true);
+    void drawStatus(WINDOW *win, const string& iMessage, bool error = true);
     // Draw the board, with the coordinates
     void drawBoard(WINDOW *win, int y, int x) const;
     // Draw the boxes for scores and racks
     void drawScoresRacks(WINDOW *win, int y, int x) const;
     // Draw the results panel
-    void drawResults(WINDOW *win, int y, int x);
+    void drawResults(Box &ioBox) const;
     // Draw the history panel
-    void drawHistory(WINDOW *win, int y, int x);
+    void drawHistory(Box &ioBox) const;
     // Draw the help panel
-    void drawHelp(WINDOW *win, int y, int x);
+    void drawHelp(Box &ioBox) const;
+    // Draw the bag panel
+    void drawBag(Box &ioBox) const;
+
+    // Change the inner state, and initialize the corresponding box
+    void setState(State iState);
     // Draw the "Play word" box, and handle the played word
     void playWord(WINDOW *win, int y, int x);
     void checkWord(WINDOW *win, int y, int x);
@@ -82,6 +144,7 @@
     void loadGame(WINDOW *win, int y, int x);
     void passTurn(WINDOW *win, int y, int x, FreeGame &iGame);
     void setRack(WINDOW *win, int y, int x, Training &iGame);
+
     // Get a string from the user, with a maximum length
     // The string is validated if the user presses Enter (return value: true)
     // and it is cancelled if the user presses Esc (return value: false)
@@ -110,14 +173,8 @@
     State m_state;
     // True when the user requested to quit
     bool m_dying;
-    // Index of the first line of data to be displayed in the current box
-    int m_boxStart;
-    // Number of lines of the current box (border excluded)
-    int m_boxLines;
-    // Number of lines of the data to be displayed in the current box
-    int m_boxLinesData;
-    // Index of the first line of the box where to write
-    int m_boxY;
+    // Scrolling box for the current panel
+    Box m_box;
     // True if dots must be shown on empty squares
     bool m_showDots;
 };




reply via email to

[Prev in Thread] Current Thread [Next in Thread]