/* * whistory.c -- Move list window for WinBoard * $Id$ * * Copyright 1995 Free Software Foundation, Inc. * * ------------------------------------------------------------------------ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * ------------------------------------------------------------------------ */ #include "config.h" #include /* required for all Windows applications */ #include #include #include #include #include #include #include #include #include "common.h" #include "winboard.h" #include "frontend.h" #include "backend.h" #include "analyst.h" #include "whistory.h" /* Module globals */ int historyX, historyY, historyW, historyH; /* Imports from winboard.c */ extern HINSTANCE hInst; extern HWND hwndMain; void HistoryPopDown P((void)); #define HISTORY_TIMER_ID 80 struct History{ HWND dialog; char up; char moveblack; unsigned long flags[MAX_MOVES]; int idletimer; int lastline; int lastselected; int lastmove; char last_has_tactic; char last_has_mate; int first;// necessary? int current; int process_click; }; extern char *commentList[]; struct History history={0}; static int FlagB(int line) { return history.flags[line] & 0x80000000; } static int FlagW(int line) { return history.flags[line] & 0x40000000; } static int FlagComment(int line) { return history.flags[line] & 0x20000000; } static int FlagMoveNum(int line) { return history.flags[line] & 0x0000ffff; } static void SetBWFlag(int line) { history.flags[line] &= 0x3fffffff; history.flags[line] |= 0xC0000000; } static void SetBFlag(int line) { history.flags[line] &= 0x3fffffff; history.flags[line] |= 0x80000000; } static void SetWFlag(int line) { history.flags[line] &= 0x3fffffff; history.flags[line] |= 0x40000000; } static void SetCommentFlag(int line) { history.flags[line] &= 0xDfffffff; history.flags[line] |= 0x20000000; } static void SetMoveNumFlag(int movenum, int line) { history.flags[line] &= 0xffff0000; history.flags[line] |= movenum; } static void AddMoveW(int movenum, char movelist[][2*MOVE_LEN]) { // movenum is the last move (1-based) char line[MOVE_LEN+5]; history.lastline++; if (appData.debugMode) sprintf(line,"line %d (%d) %0.3d. %s", history.lastline, movenum-1, movenum/2+1,movelist); else sprintf(line,"%d. %s", movenum/2+1,movelist); SendDlgItemMessage(history.dialog, OPT_HistoryText, LB_ADDSTRING, (WPARAM) 0, (LPARAM) line); history.lastmove = movenum; // we store which move (0-based) is in the beginning of this line SetMoveNumFlag(movenum-1, history.lastline); SetWFlag(history.lastline); } static void AddMoveB(int movenum, char movelist[][2*MOVE_LEN]) { char line[MOVE_LEN+5]; history.lastline++; if (appData.debugMode) sprintf(line,"line %d (%d) %0.3d. ... %s", history.lastline, movenum-1, movenum/2, movelist); else sprintf(line,"%d. ... %s", movenum/2, movelist); SendDlgItemMessage(history.dialog, OPT_HistoryText, LB_ADDSTRING, (WPARAM) 0, (LPARAM) line); history.lastmove = movenum; // we store which move (0-based) is in the beginning of this line SetMoveNumFlag(movenum-1, history.lastline); SetBFlag(history.lastline); } static void AddMoveBW(int movenum, char movelist[][2*MOVE_LEN]) { // movenum is the last move (1-based) char line[MOVE_LEN+MOVE_LEN+40]; // two moves history.lastline++; if (appData.debugMode) sprintf(line,"line %d (%d) %0.3d. %s %s",history.lastline, movenum-2, movenum/2,movelist-1,movelist); else sprintf(line,"%d. %s %s",movenum/2,movelist-1,movelist); SendDlgItemMessage(history.dialog, OPT_HistoryText, LB_ADDSTRING, (WPARAM) 0, (LPARAM) line); history.lastmove = movenum; // we store which move (0-based) is in the beginning of this line SetMoveNumFlag(movenum-2, history.lastline); SetBWFlag(history.lastline); } static void DeleteLastLine() { SendDlgItemMessage(history.dialog, OPT_HistoryText, LB_DELETESTRING, (WPARAM) history.lastline, (LPARAM) 0); history.lastline--; } static int HasComment(int movenum) { return commentList[movenum]!=0; } static void AddComment(int movenum) { char *comment = commentList[movenum]; char buf[100]; char *str = &buf[0]; strncpy(buf,comment,98); buf[98]=0; while (*str) { if (*str == '\n' || *str == '\r') *str = ' '; str++; } SendDlgItemMessage(history.dialog, OPT_HistoryText, LB_ADDSTRING, (WPARAM) 0, (LPARAM) buf); history.lastline++; SetMoveNumFlag(movenum, history.lastline); SetCommentFlag(history.lastline); } static void AddMove(int movenum, char movelist[][2*MOVE_LEN]) { // movenum is 1 based! if (!(movenum & 1) ) // even moves { if (movenum > 0 && HasComment(movenum-1)) { AddMoveB(movenum, movelist); } else { DeleteLastLine(); AddMoveBW(movenum, movelist); } if (HasComment(movenum)) AddComment(movenum); } else { AddMoveW(movenum, movelist); if (HasComment(movenum)) AddComment(movenum); } } static void InitHistory() { int i; if (history.dialog) SendDlgItemMessage(history.dialog, OPT_HistoryText, LB_RESETCONTENT, 0, 0); history.lastline = -1; history.lastmove = 0; history.lastselected = -1; history.process_click = 0; for (i=0; i < MAX_MOVES; i++) { history.flags[i] = 0; } } static void HighlightLine(int current_move) { int i; int is_black = current_move & 1; int sel_line = history.lastline; for (i = 0; i < history.lastline; i++) { if (FlagComment(i)) continue; if (FlagMoveNum(i)==current_move) { sel_line = i; break; } else if (is_black&&FlagMoveNum(i)==current_move-1 && FlagB(i)) { sel_line = i; } } if (sel_line!= history.lastselected) { history.lastselected = sel_line; SendDlgItemMessage(history.dialog, OPT_HistoryText, LB_SETCURSEL, sel_line, 0); } } void HistorySet(char movelist[][2*MOVE_LEN], int first, int last, int current) { int i; if (!HistoryDialog()) return; // check if processing mouse click or beginning of game if (history.process_click || current < 0) return; if (last < history.lastmove // are we truncating || (first==0 && last==0 && current==-1)) { InitHistory(); } if (last > history.lastmove) { for (i = history.lastmove + 1; i <= last; i++) { AddMove(i, &movelist[i-1]); } history.lastselected = history.lastline; SendDlgItemMessage(history.dialog, OPT_HistoryText, LB_SETCURSEL, history.lastselected, 0); } HighlightLine(current); } static void HistoryClick(int n) { int move_num = FlagMoveNum(n); history.process_click = 1; if (FlagComment(n)) { } else { if (history.moveblack && FlagB(n) && FlagW(n)) move_num+=2; // go to black moves else move_num+=1;// go to white moves } ToNrEvent(move_num); history.process_click = 0; } static void CheckListSelection() { if (history.dialog) { int sel = SendDlgItemMessage(history.dialog, OPT_HistoryText, LB_GETCURSEL, 0, 0); if (sel>=0 && sel!=history.lastselected) { history.lastselected = sel; HistoryClick(sel); } } } void ReinitHistory() { InitHistory(); if (currentMove > 0) { BackwardEvent(); ForwardEvent(); } else { ForwardEvent(); BackwardEvent(); } } LRESULT CALLBACK HistoryDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static HANDLE hwndText; static int sizeX, sizeY; int newSizeX, newSizeY; MINMAXINFO *mmi; RECT rect; switch (message) { case WM_INITDIALOG: /* Initialize the dialog items */ if (!history.dialog) { history.dialog = hDlg; CheckDlgButton(hDlg,IDC_WHITE_MOVE, 1); history.idletimer = SetTimer(history.dialog, (UINT) HISTORY_TIMER_ID, (UINT) 300 /*millisec*/, NULL); GetClientRect(hDlg, &rect); sizeX = rect.right; sizeY = rect.bottom; if (historyX != CW_USEDEFAULT) { WINDOWPLACEMENT wp; EnsureOnScreen(&historyX, &historyY); wp.length = sizeof(WINDOWPLACEMENT); wp.flags = 0; wp.showCmd = SW_SHOW; wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0; wp.rcNormalPosition.left = historyX; wp.rcNormalPosition.right = historyX + historyW; wp.rcNormalPosition.top = historyY; wp.rcNormalPosition.bottom = historyY + historyH; SetWindowPlacement(hDlg, &wp); GetClientRect(hDlg, &rect); newSizeX = rect.right; newSizeY = rect.bottom; ResizeEditPlusButtons(hDlg, GetDlgItem(hDlg, OPT_HistoryText), sizeX, sizeY, newSizeX, newSizeY); sizeX = newSizeX; sizeY = newSizeY; } } return FALSE; case WM_SIZE: newSizeX = LOWORD(lParam); newSizeY = HIWORD(lParam); ResizeEditPlusButtons(hDlg, GetDlgItem(hDlg, OPT_HistoryText), sizeX, sizeY, newSizeX, newSizeY); sizeX = newSizeX; sizeY = newSizeY; break; case WM_GETMINMAXINFO: /* Prevent resizing window too small */ mmi = (MINMAXINFO *) lParam; mmi->ptMinTrackSize.x = 100; mmi->ptMinTrackSize.y = 100; break; case WM_TIMER: switch (wParam) { case HISTORY_TIMER_ID: CheckListSelection(); break; } break; case WM_COMMAND: switch (LOWORD(wParam)) { case OPT_HistoryReinit: ReinitHistory(); break; case IDCANCEL: HistoryPopDown(); return TRUE; case IDC_BLACK_MOVE: history.moveblack = 1; history.lastselected = -1; break; case IDC_WHITE_MOVE: history.moveblack = 0; history.lastselected = -1; break; default: return FALSE; } return TRUE; default: break; } return FALSE; } BOOLEAN IsHistoryWindUp() { return history.up; } HWND HistoryDialog() { return history.dialog; } VOID HistoryPopUp() { FARPROC lpProc; CheckMenuItem(GetMenu(hwndMain), IDM_ShowHistory, MF_CHECKED); if (history.dialog) { SendMessage(history.dialog, WM_INITDIALOG, 0, 0); if (!history.up) ShowWindow(history.dialog, SW_SHOW); } else { lpProc = MakeProcInstance((FARPROC)HistoryDialogProc, hInst); CreateDialog(hInst, MAKEINTRESOURCE(DLG_History), hwndMain, (DLGPROC)lpProc); FreeProcInstance(lpProc); } history.up = TRUE; } VOID HistoryPopDown(void) { CheckMenuItem(GetMenu(hwndMain), IDM_ShowHistory, MF_UNCHECKED); if (history.dialog) ShowWindow(history.dialog, SW_HIDE); history.up = FALSE; } VOID HistoryHighlight(int index) { if (history.dialog == NULL) return; SendDlgItemMessage(history.dialog, OPT_HistoryText, LB_SETCURSEL, index - 1, 0); } VOID HistoryDestroy() { HistoryPopDown(); } VOID ShowHistoryProc() { if (history.up) { HistoryPopDown(); } else { HistoryPopUp(); } }