[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Eliot-dev] Changes to eliot/utils/ncurses.cpp [antoine-1]
From: |
eliot-dev |
Subject: |
[Eliot-dev] Changes to eliot/utils/ncurses.cpp [antoine-1] |
Date: |
Sun, 23 Oct 2005 13:16:42 -0400 |
Index: eliot/utils/ncurses.cpp
diff -u /dev/null eliot/utils/ncurses.cpp:1.12.2.1
--- /dev/null Sun Oct 23 17:16:42 2005
+++ eliot/utils/ncurses.cpp Sun Oct 23 17:16:24 2005
@@ -0,0 +1,887 @@
+/*****************************************************************************
+ * Copyright (C) 2005 Eliot
+ * Authors: Olivier Teuliere <address@hidden>
+ *
+ * $Id: ncurses.cpp,v 1.12.2.1 2005/10/23 17:16:24 afrab Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *****************************************************************************/
+
+#include "config.h"
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) gettext(String)
+#else
+# define _(String) String
+#endif
+
+#include <ctype.h>
+#include <fstream>
+
+#include "ncurses.h"
+#include "dic.h"
+#include "dic_search.h"
+#include "game_factory.h"
+#include "training.h"
+#include "duplicate.h"
+#include "freegame.h"
+
+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)
+{
+}
+
+
+CursesIntf::~CursesIntf()
+{
+ GameFactory::Instance()->releaseGame(*m_game);
+}
+
+
+void CursesIntf::drawBox(WINDOW *win, int y, int x, int h, int w,
+ const string& iTitle)
+{
+ if (w > 3 && h > 2)
+ {
+ int i_len = iTitle.size();
+
+ 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);
+
+ 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);
+ }
+}
+
+
+void CursesIntf::clearRect(WINDOW *win, int y, int x, int h, int w)
+{
+ for (int i = 0; i < h; i++)
+ {
+ mvwhline(win, y + i, x, ' ', w);
+ }
+}
+
+
+void CursesIntf::boxPrint(WINDOW *win, int y, int x, const char *fmt, ...)
+{
+ 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);
+}
+
+
+void CursesIntf::drawStatus(WINDOW *win, int y, int x,
+ const string& iMessage, bool error)
+{
+ if (error)
+ wattron(win, COLOR_PAIR(COLOR_YELLOW));
+ mvwprintw(win, y, x, iMessage.c_str());
+ whline(win, ' ', COLS - x - 1 - iMessage.size());
+ if (error)
+ wattron(win, COLOR_PAIR(COLOR_WHITE));
+}
+
+
+void CursesIntf::drawBoard(WINDOW *win, int y, int x) const
+{
+ // Box around the board
+ drawBox(win, y + 1, x + 3, 17, 47, "");
+
+ // Print the coordinates
+ for (int i = 0; i < 15; i++)
+ {
+ mvwaddch(win, y + i + 2, x + 1, 'A' + i);
+ mvwaddch(win, y + i + 2, x + 51, 'A' + i);
+ mvwprintw(win, y, x + 3 * i + 5, "%d", i + 1);
+ mvwprintw(win, y + 18, x + 3 * i + 5, "%d", i + 1);
+ }
+
+ // The board itself
+ Board board = m_game->getBoard();
+ for (int row = 1; row < 16; row++)
+ {
+ for (int col = 1; col < 16; col++)
+ {
+ // Handle colors
+ int wm = board.getWordMultiplier(row, col);
+ int lm = board.getLetterMultiplier(row, col);
+ if (wm == 3)
+ wattron(win, COLOR_PAIR(COLOR_RED));
+ else if (wm == 2)
+ wattron(win, COLOR_PAIR(COLOR_MAGENTA));
+ else if (lm == 3)
+ wattron(win, COLOR_PAIR(COLOR_BLUE));
+ else if (lm == 2)
+ wattron(win, COLOR_PAIR(COLOR_CYAN));
+ else
+ wattron(win, COLOR_PAIR(COLOR_WHITE));
+
+ // Empty square
+ mvwprintw(win, y + row + 1, x + 3 * col + 1, " ");
+
+ // Now add the letter
+ char c = board.getChar(row, col);
+ if (c)
+ {
+ if (islower(c))
+ mvwaddch(win, y + row + 1, x + 3 * col + 2,
+ c | A_BOLD | COLOR_PAIR(COLOR_GREEN));
+ else
+ mvwaddch(win, y + row + 1, x + 3 * col + 2, c);
+ }
+ else
+ {
+ // Empty square... should we display a dot?
+ if (m_showDots)
+ mvwaddch(win, y + row + 1, x + 3 * col + 2, '.');
+ }
+ }
+ }
+ wattron(win, COLOR_PAIR(COLOR_WHITE));
+}
+
+
+void CursesIntf::drawScoresRacks(WINDOW *win, int y, int x) const
+{
+ drawBox(win, y, x, m_game->getNPlayers() + 2, 25, _(" Scores "));
+ for (int i = 0; i < m_game->getNPlayers(); i++)
+ {
+ if (m_game->getMode() != Game::kTRAINING && i ==
m_game->getCurrentPlayer())
+ attron(A_BOLD);
+ mvwprintw(win, y + i + 1, x + 2,
+ _("Player %d: %d"), i, m_game->getPlayerPoints(i));
+ if (m_game->getMode() != Game::kTRAINING && i ==
m_game->getCurrentPlayer())
+ attroff(A_BOLD);
+ }
+
+ // Distance between the 2 boxes
+ int yOff = m_game->getNPlayers() + 3;
+
+ drawBox(win, y + yOff, x, m_game->getNPlayers() + 2, 25, _(" Racks "));
+ for (int i = 0; i < m_game->getNPlayers(); i++)
+ {
+ if (m_game->getMode() != Game::kTRAINING && i ==
m_game->getCurrentPlayer())
+ attron(A_BOLD);
+ mvwprintw(win, y + yOff + i + 1, x + 2,
+ _("Player %d: %s"), i, m_game->getPlayerRack(i).c_str());
+ if (m_game->getMode() != Game::kTRAINING && i ==
m_game->getCurrentPlayer())
+ attroff(A_BOLD);
+ // Force to refresh the whole rack
+ whline(win, ' ', 7 - m_game->getPlayerRack(i).size());
+ }
+
+ // Display a message when the search is complete
+ if (m_game->getMode() == Game::kTRAINING &&
+ static_cast<Training*>(m_game)->getNResults())
+ {
+ mvwprintw(win, y + 2*yOff - 1, x + 2, _("Search complete"));
+ }
+ else
+ mvwhline(win, y + 2*yOff - 1, x + 2, ' ', strlen(_("Search
complete")));
+}
+
+
+void CursesIntf::drawResults(WINDOW *win, int y, int x)
+{
+ if (m_game->getMode() != Game::kTRAINING)
+ return;
+ Training *tr_game = static_cast<Training*>(m_game);
+
+ int h = 17;
+ drawBox(win, y, x, h, 25, _(" Search results "));
+ m_boxY = y + 1;
+ m_boxLines = h - 2;
+ m_boxLinesData = tr_game->getNResults();
+
+ int i;
+ for (i = m_boxStart; i < tr_game->getNResults() &&
+ i < m_boxStart + m_boxLines; i++)
+ {
+ string coord = tr_game->getSearchedCoords(i);
+ boxPrint(win, i, x + 1, "%3d %s%s %3s",
+ tr_game->getSearchedPoints(i),
+ tr_game->getSearchedWord(i).c_str(),
+ string(h - 3 - tr_game->getSearchedWord(i).size(), '
').c_str(),
+ coord.c_str());
+ }
+ // Complete the list with empty lines, to avoid trails
+ for (; i < m_boxStart + m_boxLines; i++)
+ {
+ boxPrint(win, i, x + 1, string(23, ' ').c_str());
+ }
+}
+
+
+void CursesIntf::drawHistory(WINDOW *win, int y, int x)
+{
+ // To allow pseudo-scrolling, without leaving trails
+ clear();
+
+ 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->getNRounds();
+
+ // Heading
+ boxPrint(win, m_boxStart, x + 2,
+ _(" N | RACK | SOLUTION | REF | PTS | P | BONUS"));
+ mvwhline(win, y + 2, x + 2, ACS_HLINE, 55);
+
+ int i;
+ for (i = m_boxStart + 0; i < m_game->getNRounds() &&
+ i < m_boxStart + m_boxLines; i++)
+ {
+ string word = m_game->getPlayedWord(i);
+ string coord = m_game->getPlayedCoords(i);
+ boxPrint(win, i + 2, x + 2,
+ "%2d %8s %s%s %3s %3d %1d %c",
+ i + 1, m_game->getPlayedRack(i).c_str(), word.c_str(),
+ string(15 - word.size(), ' ').c_str(),
+ coord.c_str(), m_game->getPlayedPoints(i),
+ m_game->getPlayedPlayer(i),
+ m_game->getPlayedBonus(i) ? '*' : ' ');
+ }
+ 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));
+}
+
+
+void CursesIntf::drawHelp(WINDOW *win, int y, int x)
+{
+ // 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;
+
+ 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"));
+
+ m_boxLinesData = n;
+}
+
+
+void CursesIntf::playWord(WINDOW *win, int y, int x)
+{
+ drawBox(win, y, x, 4, 32, _(" Play a word "));
+ mvwprintw(win, y + 1, x + 2, _("Played word:"));
+ mvwprintw(win, y + 2, x + 2, _("Coordinates:"));
+ wrefresh(win);
+
+ // TRANSLATORS: Align the : when translating "Played word:" and
+ // "Coordinates:". For example:
+ // Pl. word :
+ // Coordinates:
+ int l1 = strlen(_("Played word:"));
+ int l2 = strlen(_("Coordinates:"));
+ int xOff;
+ if (l1 > l2)
+ xOff = l1 + 3;
+ else
+ xOff = l2 + 3;
+
+ string word, coord;
+ if (readString(win, y + 1, x + xOff, 15, word) &&
+ readString(win, y + 2, x + xOff, 3, coord))
+ {
+ int res = m_game->play(coord, word);
+ if (res)
+ {
+ drawStatus(win, LINES - 1, 0, _("Incorrect or misplaced word"));
+ }
+ }
+ m_state = DEFAULT;
+ clearRect(win, y, x, 4, 32);
+}
+
+
+void CursesIntf::checkWord(WINDOW *win, int y, int x)
+{
+ drawBox(win, y, x, 4, 32, _(" Dictionary "));
+ mvwprintw(win, y + 1, x + 2, _("Enter the word to check:"));
+ wrefresh(win);
+
+ string word;
+ if (readString(win, y + 2, x + 2, 15, word))
+ {
+ int res = Dic_search_word(m_game->getDic(), word.c_str());
+ char s[100];
+ if (res)
+ snprintf(s, 100, _("The word '%s' exists"), word.c_str());
+ else
+ snprintf(s, 100, _("The word '%s' does not exist"), word.c_str());
+ drawStatus(win, LINES - 1, 0, s);
+ }
+ m_state = DEFAULT;
+ clearRect(win, y, x, 4, 32);
+}
+
+
+void CursesIntf::saveGame(WINDOW *win, int y, int x)
+{
+ drawBox(win, y, x, 4, 32, _(" Save the game "));
+ mvwprintw(win, y + 1, x + 2, _("Enter the file name:"));
+ wrefresh(win);
+
+ string filename;
+ if (readString(win, y + 2, x + 2, 28, filename, kFILENAME))
+ {
+ ofstream fout(filename.c_str());
+ char s[100];
+ if (fout.rdstate() == ios::failbit)
+ {
+ snprintf(s, 100, _("Cannot open file %s for writing"),
+ filename.c_str());
+ }
+ else
+ {
+ m_game->save(fout);
+ fout.close();
+ snprintf(s, 100, _("Game saved in %s"), filename.c_str());
+ }
+ drawStatus(win, LINES - 1, 0, s);
+ }
+ m_state = DEFAULT;
+ clearRect(win, y, x, 4, 32);
+}
+
+
+void CursesIntf::loadGame(WINDOW *win, int y, int x)
+{
+ drawBox(win, y, x, 4, 32, _(" Load a game "));
+ mvwprintw(win, y + 1, x + 2, _("Enter the file name:"));
+ wrefresh(win);
+
+ string filename;
+ if (readString(win, y + 2, x + 2, 28, filename, kFILENAME))
+ {
+ char s[100];
+ FILE *fin;
+ if ((fin = fopen(filename.c_str(), "r")) == NULL)
+ {
+ snprintf(s, 100, _("Cannot open file %s for reading"),
+ filename.c_str());
+ }
+ else
+ {
+ Game *loaded = Game::load(fin, m_game->getDic());
+ if (loaded == NULL)
+ {
+ snprintf(s, 100, _("Invalid saved game"));
+ }
+ else
+ {
+ snprintf(s, 100, _("Game loaded"));
+ GameFactory::Instance()->releaseGame(*m_game);
+ m_game = loaded;
+ }
+ fclose(fin);
+ }
+ drawStatus(win, LINES - 1, 0, s);
+ }
+ m_state = DEFAULT;
+ clearRect(win, y, x, 4, 32);
+}
+
+
+void CursesIntf::passTurn(WINDOW *win, int y, int x, FreeGame &iGame)
+{
+ drawBox(win, y, x, 4, 32, _(" Pass your turn "));
+ mvwprintw(win, y + 1, x + 2, _("Enter the letters to change:"));
+ wrefresh(win);
+
+ string letters;
+ if (readString(win, y + 2, x + 2, 7, letters))
+ {
+ int res = iGame.pass(letters, m_game->getCurrentPlayer());
+ if (res)
+ {
+ drawStatus(win, LINES - 1, 0, _("Cannot pass the turn"));
+ }
+ }
+ m_state = DEFAULT;
+ clearRect(win, y, x, 4, 32);
+}
+
+
+void CursesIntf::setRack(WINDOW *win, int y, int x, Training &iGame)
+{
+ drawBox(win, y, x, 4, 32, _(" Set rack "));
+ mvwprintw(win, y + 1, x + 2, _("Enter the new letters:"));
+ wrefresh(win);
+
+ string letters;
+ if (readString(win, y + 2, x + 2, 7, letters, kJOKER))
+ {
+ iGame.setRackManual(0, false, letters);
+ }
+ m_state = DEFAULT;
+ clearRect(win, y, x, 4, 32);
+}
+
+
+bool CursesIntf::readString(WINDOW *win, int y, int x, int n, string &oString,
+ unsigned int flag)
+{
+ int c;
+ wmove(win, y, x);
+ curs_set(1);
+ while ((c = getch()) != 0)
+ {
+ if (c == 0x1b ) // Esc
+ {
+ curs_set(0);
+ return false;
+ }
+ else if (c == KEY_ENTER || c == 0xD)
+ {
+ curs_set(0);
+ return true;
+ }
+ else if (c == 0x0c) // Ctrl-L
+ {
+// clear();
+ redraw(win);
+ wmove(win, y, x);
+ }
+ else if (c == KEY_BACKSPACE && oString.size() > 0)
+ {
+ x--;
+ mvwprintw(win, y, x, " ");
+ wmove(win, y, x);
+ oString.erase(oString.size() - 1);
+ }
+ else if (isalnum(c) && oString.size() < (unsigned int)n)
+ {
+ mvwprintw(win, y, x, "%c", c);
+ x++;
+ oString += (char)c;
+ }
+ else
+ {
+ if (flag & kJOKER && c == '?')
+ {
+ mvwprintw(win, y, x, "%c", c);
+ x++;
+ oString += (char)c;
+ }
+ if (flag & kFILENAME)
+ {
+ if (c == '/' || c == '.' || c == '-' || c == '_' || c == ' ')
+ {
+ mvwprintw(win, y, x, "%c", c);
+ x++;
+ oString += (char)c;
+ }
+ }
+ }
+// else
+// mvwprintw(win, 0, 0, "%3d", c);
+ }
+ curs_set(0);
+ return 0;
+}
+
+
+int CursesIntf::handleKeyForGame(int iKey, Training &iGame)
+{
+ switch (iKey)
+ {
+ case '*':
+ iGame.setRackRandom(0, false, Game::RACK_ALL);
+ return 1;
+
+ case '+':
+ iGame.setRackRandom(0, false, Game::RACK_NEW);
+ return 1;
+
+ case 't':
+ case 'T':
+ setRack(m_win, 22, 10, iGame);
+ return 1;
+
+ case 'c':
+ case 'C':
+ iGame.search();
+ return 1;
+
+ default:
+ return 2;
+ }
+}
+
+
+int CursesIntf::handleKeyForGame(int iKey, Duplicate &iGame)
+{
+ switch (iKey)
+ {
+ case 'n':
+ case 'N':
+ iGame.nextHumanPlayer();
+ return 1;
+
+ default:
+ return 2;
+ }
+}
+
+
+int CursesIntf::handleKeyForGame(int iKey, FreeGame &iGame)
+{
+ switch (iKey)
+ {
+ case 'p':
+ case 'P':
+ passTurn(m_win, 22, 10, iGame);
+ return 1;
+
+ default:
+ return 2;
+ }
+}
+
+
+int CursesIntf::handleKey(int iKey)
+{
+ if (m_state == DEFAULT)
+ {
+ int res;
+ if (m_game->getMode() == Game::kTRAINING)
+ {
+ res = handleKeyForGame(iKey, (Training&)*m_game);
+ }
+ else if (m_game->getMode() == Game::kDUPLICATE)
+ {
+ res = handleKeyForGame(iKey, (Duplicate&)*m_game);
+ }
+ else
+ {
+ res = handleKeyForGame(iKey, (FreeGame&)*m_game);
+ }
+
+ if (res != 2)
+ return res;
+ }
+ else // m_state is in {HELP, RESULTS, HISTORY}
+ {
+ switch (iKey)
+ {
+ case KEY_HOME:
+ if (m_boxLinesData <= m_boxLines && m_boxStart > 0)
+ return 0;
+ m_boxStart = 0;
+ return 1;
+ case KEY_END:
+ if (m_boxLinesData <= m_boxLines &&
+ m_boxStart < m_boxLinesData - 1)
+ return 0;
+ m_boxStart = m_boxLinesData - 1;
+ return 1;
+ case KEY_UP:
+ if (m_boxLinesData <= m_boxLines || m_boxStart <= 0)
+ return 0;
+ m_boxStart--;
+ return 1;
+ case KEY_DOWN:
+ if (m_boxLinesData <= m_boxLines ||
+ m_boxStart >= m_boxLinesData - 1)
+ return 0;
+ m_boxStart++;
+ return 1;
+ case KEY_PPAGE:
+ if (m_boxLinesData <= m_boxLines)
+ return 0;
+ m_boxStart -= m_boxLines;
+ if (m_boxStart < 0)
+ m_boxStart = 0;
+ return 1;
+ 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;
+ }
+ }
+
+ switch (iKey)
+ {
+ // Toggle help
+ case 'h':
+ case 'H':
+ case '?':
+ if (m_state == HELP)
+ m_state = DEFAULT;
+ else
+ m_state = HELP;
+ m_boxStart = 0;
+ clear();
+ return 1;
+
+ // Toggle history
+ case 'y':
+ case 'Y':
+ if (m_state == HISTORY)
+ m_state = DEFAULT;
+ else
+ m_state = HISTORY;
+ m_boxStart = 0;
+ clear();
+ return 1;
+
+ // Toggle results (training mode only)
+ case 'r':
+ case 'R':
+ if (m_game->getMode() != Game::kTRAINING)
+ return 0;
+ if (m_state == RESULTS)
+ m_state = DEFAULT;
+ else
+ m_state = RESULTS;
+ m_boxStart = 0;
+ clear();
+ return 1;
+
+ // Toggle dots display
+ case 'e':
+ case 'E':
+ m_showDots = !m_showDots;
+ return 1;
+
+ // Check a word in the dictionary
+ case 'd':
+ case 'D':
+ if (m_state != DEFAULT)
+ return 0;
+ checkWord(m_win, 22, 10);
+ return 1;
+
+ // Play a word
+ case 'j':
+ case 'J':
+ if (m_state != DEFAULT)
+ return 0;
+ playWord(m_win, 22, 10);
+ return 1;
+
+ // Ctrl-L should clear and redraw the screen
+ case 0x0c:
+ clear();
+ return 1;
+
+ case 'l':
+ case 'L':
+ if (m_state != DEFAULT)
+ return 0;
+ loadGame(m_win, 22, 10);
+ return 1;
+
+ case 's':
+ case 'S':
+ if (m_state != DEFAULT)
+ return 0;
+ saveGame(m_win, 22, 10);
+ return 1;
+
+ // Quit
+ case 'q':
+ case 'Q':
+ case 0x1b: // Esc
+ m_dying = true;
+ return 0;
+
+ default:
+ return 0;
+ }
+}
+
+
+void CursesIntf::redraw(WINDOW *win)
+{
+ if (m_state == DEFAULT)
+ {
+ drawScoresRacks(win, 3, 54);
+ drawBoard(win, 2, 0);
+ }
+ else if (m_state == RESULTS)
+ {
+ drawResults(win, 3, 54);
+ drawBoard(win, 2, 0);
+ }
+ else if (m_state == HELP)
+ {
+ drawHelp(win, 1, 0);
+ }
+ else if (m_state == HISTORY)
+ {
+ drawHistory(win, 1, 0);
+ }
+
+ // Title
+ attron(A_REVERSE);
+ string mode;
+ if (m_game->getMode() == Game::kTRAINING)
+ mode = _("Training mode");
+ else if (m_game->getMode() == Game::kFREEGAME)
+ mode = _("Free game mode");
+ else if (m_game->getMode() == Game::kDUPLICATE)
+ mode = _("Duplicate mode");
+ string variant = "";
+ if (m_game->getVariant() == Game::kJOKER)
+ variant = string(" - ") + _("Joker game");
+ string title = "Eliot (" + mode + variant + ") " + _("[h for help]");
+ mvwprintw(win, 0, 0, title.c_str());
+ whline(win, ' ', COLS - title.size());
+ attroff(A_REVERSE);
+
+ wrefresh(win);
+}
+
+
+int main(int argc, char ** argv)
+{
+#ifdef HAVE_SETLOCALE
+ // Set locale via LC_ALL
+ setlocale(LC_ALL, "");
+#endif
+
+#if ENABLE_NLS
+ // Set the message domain
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+#endif
+
+ srand(time(NULL));
+
+ Game *game = GameFactory::Instance()->createFromCmdLine(argc, argv);
+ if (game == NULL)
+ return 1;
+
+ game->start();
+
+ // Initialize the ncurses library
+ WINDOW *wBoard = initscr();
+ keypad(wBoard, true);
+ // Take input chars one at a time
+ cbreak();
+ // Do not do NL -> NL/CR
+ nonl();
+ // Hide the cursor
+ curs_set(0);
+
+ if (has_colors())
+ {
+ start_color();
+
+ // Simple color assignment
+ init_pair(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK);
+ init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK);
+ init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
+ init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK);
+
+ init_pair(COLOR_BLUE, COLOR_BLACK, COLOR_BLUE);
+ init_pair(COLOR_CYAN, COLOR_BLACK, COLOR_CYAN);
+ init_pair(COLOR_MAGENTA, COLOR_BLACK, COLOR_MAGENTA);
+ init_pair(COLOR_RED, COLOR_BLACK, COLOR_RED);
+ }
+
+ // Do not echo
+ noecho();
+
+ // mainIntf will take care of destroying game for us.
+ CursesIntf mainIntf(wBoard, *game);
+ mainIntf.redraw(wBoard);
+
+ while (!mainIntf.isDying())
+ {
+ int c = getch();
+ if (mainIntf.handleKey(c) == 1)
+ {
+ mainIntf.redraw(wBoard);
+ }
+ }
+
+ delwin(wBoard);
+
+ // Exit the ncurses library
+ endwin();
+
+ GameFactory::Destroy();
+
+ return 0;
+}
- [Eliot-dev] Changes to eliot/utils/ncurses.cpp [antoine-1],
eliot-dev <=