2 * ngamelist.c -- Game list window, Xt-independent front-end code for XBoard
4 * Copyright 1995, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
5 * ------------------------------------------------------------------------
7 * GNU XBoard is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or (at
10 * your option) any later version.
12 * GNU XBoard is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see http://www.gnu.org/licenses/. *
20 *------------------------------------------------------------------------
21 ** See the file ChangeLog for a revision history. */
28 #include <sys/types.h>
33 #else /* not STDC_HEADERS */
34 extern char *getenv();
37 # else /* not HAVE_STRING_H */
39 # endif /* not HAVE_STRING_H */
40 #endif /* not STDC_HEADERS */
54 # define _(s) gettext (s)
55 # define N_(s) gettext_noop (s)
62 static char filterString[MSG_SIZ];
63 static int listLength, wins, losses, draws, page;
73 static GameListClosure *glc = NULL;
75 static char *filterPtr;
76 static char *list[1003];
79 static int GameListPrepare P((int byPos));
80 static void GameListReplace P((int page));
81 static void GL_Button P((int n));
83 static Option gamesOptions[] = {
84 { 200, LR|TB, 400, NULL, (void*) list, "", NULL, ListBox, "" },
85 { 0, 0, 100, NULL, (void*) &filterPtr, "", NULL, TextBox, "" },
86 { 2, SAME_ROW, 0, NULL, (void*) &GL_Button, NULL, NULL, Button, N_("(filter)") }, // buttons referred to by ID in value (=first) field!
87 { 3, SAME_ROW, 0, NULL, (void*) &GL_Button, NULL, NULL, Button, N_("thresholds") },
88 { 9, SAME_ROW, 0, NULL, (void*) &GL_Button, NULL, NULL, Button, N_("tags") },
89 { 4, SAME_ROW, 0, NULL, (void*) &GL_Button, NULL, NULL, Button, N_("find position") },
90 { 5, SAME_ROW, 0, NULL, (void*) &GL_Button, NULL, NULL, Button, N_("next") },
91 { 6, SAME_ROW, 0, NULL, (void*) &GL_Button, NULL, NULL, Button, N_("close") },
92 { 0, SAME_ROW | NO_OK, 0, NULL, NULL, "", NULL, EndMark , "" }
99 n = gamesOptions[n].value; // use marker in option rather than n itself, for more easy adding/deletng of buttons
100 if (n == 6) { // close
101 PopDown(GameListDlg);
104 if (n == 3) { // thresholds
105 LoadOptionsPopUp(GameListDlg);
108 if (n == 9) { // tags
109 GameListOptionsPopUp(GameListDlg);
112 index = SelectedListBoxItem(&gamesOptions[0]);
113 if (n == 7) { // load
115 DisplayError(_("No game selected"), 0);
118 } else if (n == 5) { // next
120 if (index >= listLength || !list[index]) {
121 DisplayError(_("Can't go forward any further"), 0);
124 HighlightWithScroll(&gamesOptions[0], index, listEnd);
125 } else if (n == 8) { // prev
128 DisplayError(_("Can't back up any further"), 0);
131 HighlightWithScroll(&gamesOptions[0], index, listEnd);
132 } else if (n == 2 || // filter
133 n == 4) { // find position
135 GetWidgetText(&gamesOptions[1], &text);
136 safeStrCpy(filterString, text, sizeof(filterString)/sizeof(filterString[0]));
137 GameListPrepare(n == 4); GameListReplace(0);
141 index = atoi(list[index])-1; // [HGM] filter: read true index from sequence nr of line
142 if (cmailMsgLoaded) {
143 CmailLoadGame(glc->fp, index + 1, glc->filename, True);
145 LoadGame(glc->fp, index + 1, glc->filename, True);
150 GameListCreate (char *name)
153 if(new = GenericPopUp(gamesOptions, name, GameListDlg, BoardWindow, NONMODAL, 1))
154 AddHandler(&gamesOptions[1], 4),
155 AddHandler(&gamesOptions[0], 5);
156 FocusOnWidget(&gamesOptions[0], GameListDlg);
161 GameListPrepare (int byPos)
162 { // [HGM] filter: put in separate routine, to make callable from call-back
169 if(st = glc->strings) while(*st) free(*st++);
170 nstrings = ((ListGame *) gameList.tailPred)->number;
171 glc->strings = (char **) malloc((nstrings + 1) * sizeof(char *));
173 lg = (ListGame *) gameList.head;
174 listLength = wins = losses = draws = 0;
175 if(byPos) InitSearch();
178 line = GameListLine(lg->number, &lg->gameInfo);
179 if((filterString[0] == NULLCHAR || SearchPattern( line, filterString )) && (!byPos || (pos=GameContainsPosition(glc->fp, lg)) >= 0) ) {
180 *st++ = line; // [HGM] filter: make adding line conditional.
182 if( lg->gameInfo.result == WhiteWins ) wins++; else
183 if( lg->gameInfo.result == BlackWins ) losses++; else
184 if( lg->gameInfo.result == GameIsDrawn ) draws++;
186 if(lg->number % 2000 == 0) {
188 snprintf(buf, MSG_SIZ, _("Scanning through games (%d)"), lg->number);
192 lg = (ListGame *) lg->node.succ;
194 GetTimeMark(&t2);printf("GameListPrepare %ld msec\n", SubtractTimeMarks(&t2,&t));
195 DisplayTitle("XBoard");
201 GameListReplace (int page)
203 // filter: put in separate routine, to make callable from call-back
204 char buf[MSG_SIZ], *p, **st=list;
207 if(page) *st++ = _("previous page"); else if(listLength > 1000) *st++ = "";
208 for(i=0; i<1000; i++) if( !(*st++ = glc->strings[page+i]) ) { st--; break; }
210 if(page + 1000 <= listLength) *st++ = _("next page");
213 LoadListBox(&gamesOptions[0], _("no games matched your request"));
214 HighlightWithScroll(&gamesOptions[0], listEnd > 1000, listEnd);
215 snprintf(buf, MSG_SIZ, _("%s - %d/%d games (%d-%d-%d)"), glc->filename, listLength, ((ListGame *) gameList.tailPred)->number, wins, losses, draws);
216 SetDialogTitle(GameListDlg, buf);
220 GameListPopUp (FILE *fp, char *filename)
225 glc = (GameListClosure *) calloc(1, sizeof(GameListClosure));
226 glc->x = glc->y = -1;
227 glc->filename = NULL;
230 GameListPrepare(False); // [HGM] filter: code put in separate routine
234 if (glc->filename != NULL) free(glc->filename);
235 glc->filename = StrSave(filename);
237 if (!GameListCreate(filename))
238 SetIconName(GameListDlg, filename);
241 GameListReplace(0); // [HGM] filter: code put in separate routine, and also called to set title
242 MarkMenu("Show Game List", GameListDlg);
248 if (glc == NULL) return;
249 PopDown(GameListDlg);
250 if (glc->strings != NULL) {
269 DisplayError(_("There is no game list"), 0);
272 if (shellUp[GameListDlg]) {
273 PopDown(GameListDlg);
276 GenericPopUp(NULL, NULL, GameListDlg, BoardWindow, NONMODAL, 1); // first two args ignored when shell exists!
277 MarkMenu("Show Game List", GameListDlg);
278 GameListHighlight(lastLoadGameNumber);
282 GameListClicks (int direction)
286 if (glc == NULL || listLength == 0) return 0;
287 if(direction == 100) { FocusOnWidget(&gamesOptions[0], GameListDlg); return 1; }
288 index = SelectedListBoxItem(&gamesOptions[0]);
290 if (index < 0) return;
291 if(page && (index == 0 && direction < 1 || direction == -4)) {
293 if(page < 0) page = 0; // safety
294 GameListReplace(page);
297 if(index == 1001 && direction >= 0 || listEnd == 1001 && direction == 4) {
299 GameListReplace(page);
304 int doLoad = abs(direction) == 3;
305 if(doLoad) direction /= 3;
307 if(direction < -1) index = 0;
308 if(direction > 1) index = listEnd-1;
309 if(index < 0 || index >= listEnd) return;
310 HighlightWithScroll(&gamesOptions[0], index, listEnd);
311 if(!doLoad) return 1;
313 index = atoi(list[index])-1; // [HGM] filter: read true index from sequence nr of line
314 if (cmailMsgLoaded) {
315 CmailLoadGame(glc->fp, index + 1, glc->filename, True);
317 LoadGame(glc->fp, index + 1, glc->filename, True);
326 GetWidgetText(&gamesOptions[1], &name);
327 safeStrCpy(filterString, name, sizeof(filterString)/sizeof(filterString[0]));
328 GameListPrepare(False); GameListReplace(0);
329 UnCaret(); // filter text-edit
330 FocusOnWidget(&gamesOptions[0], GameListDlg); // listbox
334 GameListHighlight (int index)
337 if (!shellUp[GameListDlg]) return;
339 while(*st && atoi(*st)<index) st++,i++;
340 HighlightWithScroll(&gamesOptions[0], i, listEnd);
344 SaveGameListAsText (FILE *f)
346 ListGame * lg = (ListGame *) gameList.head;
349 if( !glc || ((ListGame *) gameList.tailPred)->number <= 0 ) {
350 DisplayError(_("Game list not loaded or empty"), 0);
354 /* Copy the list into the global memory block */
357 lg = (ListGame *) gameList.head;
359 for (nItem = 0; nItem < ((ListGame *) gameList.tailPred)->number; nItem++){
360 char * st = GameListLineFull(lg->number, &lg->gameInfo);
361 char *line = GameListLine(lg->number, &lg->gameInfo);
362 if(filterString[0] == NULLCHAR || SearchPattern( line, filterString ) )
363 fprintf( f, "%s\n", st );
364 free(st); free(line);
365 lg = (ListGame *) lg->node.succ;