Make holdings scrollable
authorH.G.Muller <hgm@hgm-xboard.(none)>
Sun, 25 Dec 2016 16:20:30 +0000 (17:20 +0100)
committerH.G.Muller <hgm@hgm-xboard.(none)>
Fri, 13 Jan 2017 15:39:25 +0000 (16:39 +0100)
When the hand size exceeds the number of board ranks R, the holdings will
either display either the first R-1 or last R-1 piece types. The remaining
square will then act as a toggle button between the two states. If there
is indeed material that is not displayed, the toggle square will display
a Prince of the opposite color. (The idea is that themes for games needing
this feature would define this piece as a vertical arrow glyph.)

backend.c
backend.h
board.c
frontend.h
moves.c
winboard/winboard.c

index 933b07a..b7f36b2 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -261,7 +261,7 @@ void ics_update_width P((int new_width));
 extern char installDir[MSG_SIZ];
 VariantClass startVariant; /* [HGM] nicks: initial variant */
 Boolean abortMatch;
-int deadRanks, handSize;
+int deadRanks, handSize, handOffsets;
 
 extern int tinyLayout, smallLayout;
 ChessProgramStats programStats;
@@ -6359,14 +6359,14 @@ InitPosition (int redraw)
     }
     if(appData.holdingsSize >= 0) {
         i = appData.holdingsSize;
-        if(i > gameInfo.boardHeight) i = gameInfo.boardHeight;
+//        if(i > gameInfo.boardHeight) i = gameInfo.boardHeight;
         gameInfo.holdingsSize = i;
     }
     if(gameInfo.holdingsSize) gameInfo.holdingsWidth = 2;
     if(BOARD_HEIGHT > BOARD_RANKS || BOARD_WIDTH > BOARD_FILES)
         DisplayFatalError(_("Recompile to support this BOARD_RANKS or BOARD_FILES!"), 0, 2);
 
-    handSize = BOARD_HEIGHT;
+    if(!handSize) handSize = BOARD_HEIGHT;
     pawnRow = gameInfo.boardHeight - 7; /* seems to work in all common variants */
     if(pawnRow < 1) pawnRow = 1;
     if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN ||
@@ -6823,12 +6823,45 @@ InPalace (int row, int column)
 int
 PieceForSquare (int x, int y)
 {
-  if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT)
-     return -1;
-  else
+  if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) return -1;
+  if(x == BOARD_RGHT+1 && handOffsets & 1) y += handSize - BOARD_HEIGHT;
+  if(x == BOARD_LEFT-2 && !(handOffsets & 2)) y += handSize - BOARD_HEIGHT;
      return boards[currentMove][y][x];
 }
 
+ChessSquare
+More (Board board, int col, int start, int end)
+{
+    int k;
+    for(k=start; k<end; k++) if(board[k][col]) return (col == 1 ? WhiteMonarch : BlackMonarch); // arrow image
+    return EmptySquare;
+}
+
+void
+DrawPosition (int repaint, Board board)
+{
+    Board compactedBoard;
+    if(handSize > BOARD_HEIGHT && board) {
+       int k;
+       CopyBoard(compactedBoard, board);
+       if(handOffsets & 1) {
+           for(k=0; k<BOARD_HEIGHT; k++) {
+               compactedBoard[k][BOARD_WIDTH-1] = board[k+handSize-BOARD_HEIGHT][BOARD_WIDTH-1];
+               compactedBoard[k][BOARD_WIDTH-2] = board[k+handSize-BOARD_HEIGHT][BOARD_WIDTH-2];
+           }
+           compactedBoard[0][BOARD_WIDTH-1] = More(board, BOARD_WIDTH-2, 0, handSize-BOARD_HEIGHT+1);
+       } else compactedBoard[BOARD_HEIGHT-1][BOARD_WIDTH-1] = More(board, BOARD_WIDTH-2, BOARD_HEIGHT-1, handSize);
+       if(!(handOffsets & 2)) {
+           for(k=0; k<BOARD_HEIGHT; k++) {
+               compactedBoard[k][0] = board[k+handSize-BOARD_HEIGHT][0];
+               compactedBoard[k][1] = board[k+handSize-BOARD_HEIGHT][1];
+           }
+           compactedBoard[0][0] = More(board, 1, 0, handSize-BOARD_HEIGHT+1);
+       } else compactedBoard[BOARD_HEIGHT-1][0] = More(board, 1, BOARD_HEIGHT-1, handSize);
+       DrawPositionX(TRUE, compactedBoard);
+    } else DrawPositionX(repaint, board);
+}
+
 int
 OKToStartUserMove (int x, int y)
 {
@@ -7571,6 +7604,20 @@ LeftClick (ClickType clickType, int xPix, int yPix)
        x = BOARD_WIDTH - 1 - x;
     }
 
+    // map clicks in offsetted holdings back to true coords (or switch the offset)
+    if(x == BOARD_RGHT+1) {
+       if(handOffsets & 1) {
+           if(y == 0) { handOffsets &= ~1; DrawPosition(TRUE, boards[currentMove]); return; }
+           y += handSize - BOARD_HEIGHT;
+       } else if(y == BOARD_HEIGHT-1) { handOffsets |= 1; DrawPosition(TRUE, boards[currentMove]); return; }
+    }
+    if(x == BOARD_LEFT-2) {
+       if(!(handOffsets & 2)) {
+           if(y == 0) { handOffsets |= 2; DrawPosition(TRUE, boards[currentMove]); return; }
+           y += handSize - BOARD_HEIGHT;
+       } else if(y == BOARD_HEIGHT-1) { handOffsets &= ~2; DrawPosition(TRUE, boards[currentMove]); return; }
+    }
+
     if(appData.monoMouse && gameMode == EditPosition && fromX < 0 && clickType == Press && boards[currentMove][y][x] == EmptySquare) {
        static int dummy;
        RightClick(clickType, xPix, yPix, &dummy, &dummy);
@@ -9157,7 +9204,8 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h
         while(message[s] && message[s++] != ' ');
         if(BOARD_HEIGHT != h || BOARD_WIDTH != w + 4*(hand != 0) || gameInfo.holdingsSize != hand ||
            dummy == 4 && gameInfo.variant != StringToVariant(varName) ) { // engine wants to change board format or variant
-           if(hand <= h) deadRanks = 0; else deadRanks = hand - h, h = hand; // adapt board to over-sized holdings
+//         if(hand <= h) deadRanks = 0; else deadRanks = hand - h, h = hand; // adapt board to over-sized holdings
+           if(hand > h) handSize = hand; else handSize = h;
            appData.NrFiles = w; appData.NrRanks = h; appData.holdingsSize = hand;
            if(dummy == 4) gameInfo.variant = StringToVariant(varName);     // parent variant
           InitPosition(1); // calls InitDrawingSizes to let new parameters take effect
@@ -12102,6 +12150,7 @@ Reset (int redraw, int init)
     }
     pieceDefs = FALSE; // [HGM] gen: reset engine-defined piece moves
     deadRanks = 0; // assume entire board is used
+    handSize = 0;
     for(i=0; i<EmptySquare; i++) { FREE(pieceDesc[i]); pieceDesc[i] = NULL; }
     CleanupTail(); // [HGM] vari: delete any stored variations
     CommentPopDown(); // [HGM] make sure no comments to the previous game keep hanging on
@@ -15647,7 +15696,7 @@ EditPositionMenuEvent (ChessSquare selection, int x, int y)
        } else {
             if(x < BOARD_LEFT || x >= BOARD_RGHT) {
                 if(x == BOARD_LEFT-2) {
-                    if(y < BOARD_HEIGHT-1-gameInfo.holdingsSize) break;
+                    if(y < handSize-1-gameInfo.holdingsSize) break;
                     boards[0][y][1] = 0;
                 } else
                 if(x == BOARD_RGHT+1) {
@@ -18337,9 +18386,9 @@ PositionToFEN (int move, char *overrideCastling, int moveCounts)
                   *p++ = PieceToChar(piece);
         }
         for(i=0; i<gameInfo.holdingsSize; i++) { /* black holdings */
-            piece = boards[move][BOARD_HEIGHT-i-1][0];
+            piece = boards[move][handSize-i-1][0];
             if( piece != EmptySquare )
-              for(j=0; j<(int) boards[move][BOARD_HEIGHT-i-1][1]; j++)
+              for(j=0; j<(int) boards[move][handSize-i-1][1]; j++)
                   *p++ = PieceToChar(piece);
         }
 
@@ -18593,7 +18642,7 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize)
 
     /* [HGM] by default clear Crazyhouse holdings, if present */
     if(gameInfo.holdingsWidth) {
-       for(i=0; i<BOARD_HEIGHT; i++) {
+       for(i=0; i<handSize; i++) {
            board[i][0]             = EmptySquare; /* black holdings */
            board[i][BOARD_WIDTH-1] = EmptySquare; /* white holdings */
            board[i][1]             = (ChessSquare) 0; /* black counts */
@@ -18644,9 +18693,9 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize)
                     if(board[BOARD_HEIGHT-1][j] == ClearBoard) {
                         if(!bcnt) return FALSE;
                         if(n >= bcnt) n = rand() % bcnt; // use same randomization for black and white if possible
-                        for(k=0, m=n; k<gameInfo.holdingsSize; k++) if((n -= board[BOARD_HEIGHT-1-k][1]) < 0) {
-                            board[BOARD_HEIGHT-1][j] = board[BOARD_HEIGHT-1-k][0]; bcnt--;
-                            if(--board[BOARD_HEIGHT-1-k][1] == 0) board[BOARD_HEIGHT-1-k][0] = EmptySquare;
+                        for(k=0, m=n; k<gameInfo.holdingsSize; k++) if((n -= board[handSize-1-k][1]) < 0) {
+                            board[BOARD_HEIGHT-1][j] = board[handSize-1-k][0]; bcnt--;
+                            if(--board[handSize-1-k][1] == 0) board[handSize-1-k][0] = EmptySquare;
                             break;
                         }
                     }
index 74926b6..ff06dee 100644 (file)
--- a/backend.h
+++ b/backend.h
@@ -265,6 +265,7 @@ typedef struct XB_ListGame {
     GameInfo gameInfo;      /*  Note that some entries may be NULL. */
 } ListGame;
 
+extern int handSize;
 extern int border;
 extern int doubleClick;
 extern int storedGames;
diff --git a/board.c b/board.c
index 533e7fb..67e19ca 100644 (file)
--- a/board.c
+++ b/board.c
@@ -914,7 +914,7 @@ SquareExpose(int i, int j, int d)
 }
 
 void
-DrawPosition (int repaint, Board board)
+DrawPositionX (int repaint, Board board)
 {
     int i, j, do_flash, exposeAll = False;
     static int lastFlipView = 0;
index 280a1fc..fbc2e9c 100644 (file)
@@ -80,6 +80,7 @@ void DisplayIcsInteractionTitle P((String title));
 void ParseArgsFromString P((char *p));
 void ParseArgsFromFile P((FILE *f));
 void DrawPosition P((int fullRedraw, Board board));
+void DrawPositionX P((int fullRedraw, Board board));
 void ResetFrontEnd P((void));
 void NotifyFrontendLogin P((void));
 void CommentPopUp P((String title, String comment));
diff --git a/moves.c b/moves.c
index ef2f504..6461583 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -170,7 +170,7 @@ CopyBoard (Board to, Board from)
 {
     int i, j;
 
-    for (i = 0; i < BOARD_HEIGHT; i++)
+    for (i = 0; i < handSize; i++)
       for (j = 0; j < BOARD_WIDTH; j++)
        to[i][j] = from[i][j];
     for (j = 0; j < BOARD_FILES; j++) // [HGM] gamestate: copy castling rights and ep status
@@ -1826,7 +1826,7 @@ LegalDrop (Board board, int flags, ChessSquare piece, int rt, int ft)
 if(appData.debugMode) fprintf(debugFP, "LegalDrop: %d @ %d,%d)\n", piece, ft, rt);
     if(board[rt][ft] != EmptySquare) return ImpossibleMove; // must drop to empty square
     n = PieceToNumber(piece);
-    if((gameInfo.holdingsWidth == 0 || (flags & F_WHITE_ON_MOVE ? board[n][BOARD_WIDTH-1] : board[BOARD_HEIGHT-1-n][0]) != piece)
+    if((gameInfo.holdingsWidth == 0 || (flags & F_WHITE_ON_MOVE ? board[n][BOARD_WIDTH-1] : board[handSize-1-n][0]) != piece)
        && gameInfo.variant != VariantBughouse) // in bughouse we don't check for availability, because ICS doesn't always tell us
         return ImpossibleMove; // piece not available
     if(gameInfo.variant == VariantShogi) { // in Shogi lots of drops are forbidden!
index 519f924..bd829b4 100644 (file)
@@ -2068,6 +2068,7 @@ static int TranslatePieceToFontPiece( int piece )
     case WhiteSilver:\r
         return PM_WSG;\r
     case WhiteLance:\r
+\r
         return PM_WL;\r
     case WhiteFalcon:\r
         return PM_WV;\r
@@ -5352,6 +5353,7 @@ WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       SetFocus(hwndMain);\r
       break;\r
 \r
+\r
     case IDM_ToStart:\r
       ToStartEvent();\r
       SetFocus(hwndMain);\r
@@ -8874,7 +8876,7 @@ DisplayIcsInteractionTitle(char *str)
 }\r
 \r
 void\r
-DrawPosition(int fullRedraw, Board board)\r
+DrawPositionX(int fullRedraw, Board board)\r
 {\r
   HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board); \r
 }\r
@@ -9680,6 +9682,7 @@ OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
       return WSAEADDRINUSE;\r
     }\r
     if (s == INVALID_SOCKET) {\r
+\r
       if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {\r
        err = WSAGetLastError();\r
        WSACleanup();\r