Fix multi-leg promotions
[xboard.git] / ngamelist.c
index 365ed8c..3d2b417 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ngamelist.c -- Game list window, Xt-independent front-end code for XBoard
  *
- * Copyright 1995, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+ * Copyright 1995, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Free Software Foundation, Inc.
  * ------------------------------------------------------------------------
  *
  * GNU XBoard is free software: you can redistribute it and/or modify
@@ -61,6 +61,7 @@ extern char *getenv();
 
 static char filterString[MSG_SIZ];
 static int listLength, wins, losses, draws, page;
+int narrowFlag;
 
 
 typedef struct {
@@ -76,17 +77,17 @@ static char *filterPtr;
 static char *list[1003];
 static int listEnd;
 
-static int GameListPrepare P((int byPos));
+static int GameListPrepare P((int byPos, int narrow));
 static void GameListReplace P((int page));
 static void GL_Button P((int n));
 
-static Option gamesOptions[] = {
-{ 200,  LR|TB,     400, NULL, (void*) list,       "", NULL, ListBox, "" },
+Option gamesOptions[] = {
+{ 200,  LR|TB,     400, NULL, (void*) list,       NULL, NULL, ListBox, "", &appData.gameListFont },
 {   0,  0,         100, NULL, (void*) &filterPtr, "", NULL, TextBox, "" },
-{   2,  SAME_ROW,    0, NULL, (void*) &GL_Button, NULL, NULL, Button, N_("(filter)") }, // buttons referred to by ID in value (=first) field!
+{   4,  SAME_ROW,    0, NULL, (void*) &GL_Button, NULL, NULL, Button, N_("find position") },
+{   2,  SAME_ROW,    0, NULL, (void*) &GL_Button, NULL, NULL, Button, N_("narrow") }, // buttons referred to by ID in value (=first) field!
 {   3,  SAME_ROW,    0, NULL, (void*) &GL_Button, NULL, NULL, Button, N_("thresholds") },
 {   9,  SAME_ROW,    0, NULL, (void*) &GL_Button, NULL, NULL, Button, N_("tags") },
-{   4,  SAME_ROW,    0, NULL, (void*) &GL_Button, NULL, NULL, Button, N_("find position") },
 {   5,  SAME_ROW,    0, NULL, (void*) &GL_Button, NULL, NULL, Button, N_("next") },
 {   6,  SAME_ROW,    0, NULL, (void*) &GL_Button, NULL, NULL, Button, N_("close") },
 {   0,  SAME_ROW | NO_OK, 0, NULL, NULL, "", NULL, EndMark , "" }
@@ -95,7 +96,7 @@ static Option gamesOptions[] = {
 static void
 GL_Button (int n)
 {
-    int index, j;
+    int index;
     n = gamesOptions[n].value; // use marker in option rather than n itself, for more easy adding/deletng of buttons
     if (n == 6) { // close
        PopDown(GameListDlg);
@@ -129,12 +130,12 @@ GL_Button (int n)
            return;
        }
        HighlightWithScroll(&gamesOptions[0], index, listEnd);
-    } else if (n == 2 || // filter
+    } else if (n == 2 || // narrow
                n == 4) { // find position
        char *text;
        GetWidgetText(&gamesOptions[1], &text);
         safeStrCpy(filterString, text, sizeof(filterString)/sizeof(filterString[0]));
-        GameListPrepare(n == 4); GameListReplace(0);
+        GameListPrepare(True, n == 2); GameListReplace(0);
         return;
     }
 
@@ -150,15 +151,15 @@ static int
 GameListCreate (char *name)
 {
     int new;
-    if(new = GenericPopUp(gamesOptions, name, GameListDlg, BoardWindow, NONMODAL, 1))
-       AddHandler(&gamesOptions[1], 4),
-       AddHandler(&gamesOptions[0], 5);
+    if(new = GenericPopUp(gamesOptions, name, GameListDlg, BoardWindow, NONMODAL, appData.topLevel))
+       AddHandler(&gamesOptions[1], GameListDlg, 4),
+       AddHandler(&gamesOptions[0], GameListDlg, 5);
     FocusOnWidget(&gamesOptions[0], GameListDlg);
     return new;
 }
 
 static int
-GameListPrepare (int byPos)
+GameListPrepare (int byPos, int narrow)
 {   // [HGM] filter: put in separate routine, to make callable from call-back
     int nstrings;
     ListGame *lg;
@@ -175,24 +176,27 @@ GameListPrepare (int byPos)
     if(byPos) InitSearch();
     while (nstrings--) {
        int pos = -1;
-       line = GameListLine(lg->number, &lg->gameInfo);
-       if((filterString[0] == NULLCHAR || SearchPattern( line, filterString )) && (!byPos || (pos=GameContainsPosition(glc->fp, lg)) >= 0) ) {
+       if(!narrow || lg->position >= 0) { // only consider already selected positions when narrowing
+         line = GameListLine(lg->number, &lg->gameInfo);
+         if((filterString[0] == NULLCHAR || SearchPattern( line, filterString )) && (!byPos || (pos=GameContainsPosition(glc->fp, lg)) >= 0) ) {
             *st++ = line; // [HGM] filter: make adding line conditional.
            listLength++;
             if( lg->gameInfo.result == WhiteWins ) wins++; else
             if( lg->gameInfo.result == BlackWins ) losses++; else
             if( lg->gameInfo.result == GameIsDrawn ) draws++;
+           if(!byPos) pos = 0; // indicate selected
+         }
        }
        if(lg->number % 2000 == 0) {
            char buf[MSG_SIZ];
            snprintf(buf, MSG_SIZ, _("Scanning through games (%d)"), lg->number);
-           DisplayTitle(buf);
+           DisplayTitle(buf); DoEvents();
        }
        lg->position = pos;
        lg = (ListGame *) lg->node.succ;
-     }
-GetTimeMark(&t2);printf("GameListPrepare %ld msec\n", SubtractTimeMarks(&t2,&t));
-     DisplayTitle("XBoard");
+    }
+    if(appData.debugMode) { GetTimeMark(&t2);printf("GameListPrepare %ld msec\n", SubtractTimeMarks(&t2,&t)); }
+    DisplayTitle("XBoard");
     *st = NULL;
     return listLength;
 }
@@ -201,7 +205,7 @@ static void
 GameListReplace (int page)
 {
   // filter: put in separate routine, to make callable from call-back
-  char buf[MSG_SIZ], *p, **st=list;
+  char buf[MSG_SIZ], **st=list;
   int i;
 
   if(page) *st++ = _("previous page"); else if(listLength > 1000) *st++ = "";
@@ -210,24 +214,30 @@ GameListReplace (int page)
   if(page + 1000 <= listLength) *st++ = _("next page");
   *st = NULL;
 
-  LoadListBox(&gamesOptions[0], _("no games matched your request"));
+  LoadListBox(&gamesOptions[0], _("no games matched your request"), -1, -1);
   HighlightWithScroll(&gamesOptions[0], listEnd > 1000, listEnd);
   snprintf(buf, MSG_SIZ, _("%s - %d/%d games (%d-%d-%d)"), glc->filename, listLength, ((ListGame *) gameList.tailPred)->number, wins, losses, draws);
   SetDialogTitle(GameListDlg, buf);
 }
 
 void
-GameListPopUp (FILE *fp, char *filename)
+GameListUpdate ()
 {
-    char **st;
+    if(!DialogExists(GameListDlg)) return;
+    GameListPrepare(False, False);
+    GameListReplace(0);
+}
 
+void
+GameListPopUp (FILE *fp, char *filename)
+{
     if (glc == NULL) {
        glc = (GameListClosure *) calloc(1, sizeof(GameListClosure));
        glc->x = glc->y = -1;
        glc->filename = NULL;
     }
 
-    GameListPrepare(False); // [HGM] filter: code put in separate routine
+    GameListPrepare(False, False); // [HGM] filter: code put in separate routine
 
     glc->fp = fp;
 
@@ -239,13 +249,21 @@ GameListPopUp (FILE *fp, char *filename)
 
     page = 0;
     GameListReplace(0); // [HGM] filter: code put in separate routine, and also called to set title
-    MarkMenu("Show Game List", GameListDlg);
+    MarkMenu("View.GameList", GameListDlg);
+    EnableNamedMenuItem("File.SaveSelected", TRUE);
+}
+
+FILE *
+GameFile ()
+{
+  return glc ? glc->fp : NULL;
 }
 
 void
 GameListDestroy ()
 {
     if (glc == NULL) return;
+    EnableNamedMenuItem("File.SaveSelected", FALSE);
     PopDown(GameListDlg);
     if (glc->strings != NULL) {
        char **st;
@@ -262,9 +280,6 @@ GameListDestroy ()
 void
 ShowGameListProc ()
 {
-    Arg args[16];
-    int j;
-
     if (glc == NULL) {
        DisplayError(_("There is no game list"), 0);
        return;
@@ -273,8 +288,8 @@ ShowGameListProc ()
        PopDown(GameListDlg);
        return;
     }
-    GenericPopUp(NULL, NULL, GameListDlg, BoardWindow, NONMODAL, 1); // first two args ignored when shell exists!
-    MarkMenu("Show Game List", GameListDlg);
+    GenericPopUp(NULL, NULL, GameListDlg, BoardWindow, NONMODAL, appData.topLevel); // first two args ignored when shell exists!
+    MarkMenu("View.GameList", GameListDlg);
     GameListHighlight(lastLoadGameNumber);
 }
 
@@ -283,11 +298,11 @@ GameListClicks (int direction)
 {
     int index;
 
-    if (glc == NULL || listLength == 0) return 0;
+    if (glc == NULL || listLength == 0) return 1;
     if(direction == 100) { FocusOnWidget(&gamesOptions[0], GameListDlg); return 1; }
     index = SelectedListBoxItem(&gamesOptions[0]);
 
-    if (index < 0) return;
+    if (index < 0) return 1;
     if(page && (index == 0 && direction < 1 || direction == -4)) {
         page -= 1000;
         if(page < 0) page = 0; // safety
@@ -306,7 +321,7 @@ GameListClicks (int direction)
        index += direction;
        if(direction < -1) index = 0;
        if(direction >  1) index = listEnd-1;
-       if(index < 0 || index >= listEnd) return;
+       if(index < 0 || index >= listEnd) return 1;
        HighlightWithScroll(&gamesOptions[0], index, listEnd);
        if(!doLoad) return 1;
     }
@@ -325,7 +340,7 @@ SetFilter ()
         char *name;
        GetWidgetText(&gamesOptions[1], &name);
         safeStrCpy(filterString, name, sizeof(filterString)/sizeof(filterString[0]));
-        GameListPrepare(False); GameListReplace(0);
+        GameListPrepare(False, False); GameListReplace(0);
        UnCaret(); // filter text-edit
        FocusOnWidget(&gamesOptions[0], GameListDlg); // listbox
 }
@@ -353,7 +368,7 @@ SaveGameListAsText (FILE *f)
 
     /* Copy the list into the global memory block */
     if( f != NULL ) {
+
         lg = (ListGame *) gameList.head;
 
         for (nItem = 0; nItem < ((ListGame *) gameList.tailPred)->number; nItem++){
@@ -370,4 +385,3 @@ SaveGameListAsText (FILE *f)
     }
     return False;
 }
-