home *** CD-ROM | disk | FTP | other *** search
- /*
- PMICS -- PM interface for playing chess on internet chess server
- Copyright (C) 1994 Kevin Nomura
-
- 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.
-
- Author can be reached at email: chow@netcom.com
- */
- #include <stdio.h>
- #include <icolor.hpp>
- #include <icmdhdr.hpp>
- #include <istring.hpp>
- #include <irect.hpp>
- #include <ifont.hpp>
- #include <ihelp.hpp>
- #include <imsgbox.hpp>
- //#include <igroupbx.hpp>
- #include "pmics.hh"
- #include "wpmics.hh"
- #include "wboard.hh"
- #include "wcomm.hh"
- #include "session.hh"
- #define INCL_WIN
- #define INCL_WINTIMER
- #include <os2.h>
-
- IHelpWindow *helpWindow;
- IWindowHandle hMain;
- ASession *aSession;
- extern int intOption(IString s);
- extern int getIntOption(IString s, int def);
- extern IString stringOption(IString s);
-
- /***************************************************************************
- * Pushbutton labels and actions are table driven. (Currently the
- * table is statically defined, but we could make it user-customizable
- * by doing the work to externalize it -- load from file, or put in rc).
- * The actions can include substitution strings for data tracked by
- * the stat window, as follows:
- * %g game number of the present game
- ***************************************************************************/
- typedef struct {
- char label[16];
- char action[100];
- unsigned char flags;
- } ButtonInfo;
- #define BUTTONINFO_FL_RED 1
- ButtonInfo buttonInfo[NUM_PUSHBUTTONS] = {
- {"refresh", "refresh", 0},
- {"flag", "flag", 0},
- {"resign", "resign", BUTTONINFO_FL_RED},
- {"draw", "draw", 0},
- {"who abr", "who abr", 0},
- {"games", "games", 0},
- {"al", "allobservers", 0},
- {"moves", "moves %g", 0},
- {"messages","messages", 0},
- {"open", "open", 0},
- {"history", "history", 0}};
-
- /**************************************************************************
- * FUNCTION: constructor (class PmicsWindow)
- *
- * DESCRIPTION: Build main window. Divides main window into areas
- * for board, stat and comm subwindows. Initializes stat window
- * (integral to PmicsWindow class) and invokes BoardWindow ctr.
- *
- **************************************************************************/
- PmicsWindow :: PmicsWindow(unsigned long windowId)
- : IFrameWindow ( //Call the IFrameWindow constructor
- IFrameWindow::defaultStyle() // using the default style, plus
- | IFrameWindow::accelerator // accelerator key table plus
- | IFrameWindow::minimizedIcon, // get minimized icon from RC file
- windowId) // and set the main window ID
- {
- int odx, ody, idx, idy; // outside/inside dim of frame window
- int xsplit, ysplit;
- static IHelpWindow::Settings helpSettings;
- static HelpCommandHandler * helpHdr;
-
- IFUNCTRACE_DEVELOP();
- hMain = handle(); // export for messaging
-
- /**************************************************************
- * set pixel size of main window. command line flags: -x -y
- **************************************************************/
- odx = IWindow::desktopWindow()->size().coord1();
- odx = getIntOption("x", odx>800 ? 800 : odx);
- ody = getIntOption("y", IWindow::desktopWindow()->size().coord2());
- moveSizeTo(IRectangle(0, 0, odx, ody));
-
- /**************************************************************
- * divide window into 3 regions:
- * ---------------
- * | | |
- * | | |
- * | board |stat|
- * | | |
- * |-------------|
- * | |
- * | comm |
- * ---------------
- **************************************************************/
- horzCanvas = new ISplitCanvas(WND_CANVAS, this, this); // main client
- horzCanvas->setOrientation (ISplitCanvas::horizontalSplit);
- setClient(horzCanvas);
- ITRACE_DEVELOP("horzCanvas size after creation: " +
- horzCanvas->size().asString());
-
- vertCanvas = new ISetCanvas(WND_CANVAS2, horzCanvas, horzCanvas);
- vertCanvas->setDeckOrientation( ISetCanvas::horizontal )
- .setMargin( ISize(0,0) )
- .setColor( ISetCanvas::background, IColor(IColor::paleGray));
-
- int boardSize;
- // first set default, then apply explicit size if specified
- boardSize = (ody >= 768 ? 2 : 1);
- boardSize = intOption("big") ? 3 : intOption("medium") ? 2 :
- intOption("small") ? 1 : boardSize;
- boardWindow = new BoardWindow (WND_BOARD, vertCanvas, boardSize);
- setupStat(vertCanvas);
-
- commWindow = new CommWindow (WND_COMM, horzCanvas);
-
- /**************************************************************
- * adjust the window proportions to fully display the board
- **************************************************************/
- ITRACE_DEVELOP("horzCanvas size after children created: " +
- horzCanvas->size().asString());
- idx = horzCanvas->size().width();
- idy = horzCanvas->size().height();
- // xsplit = vertCanvas->splitBarThickness(ISplitCanvas::splitBarEdge)*2 +
- // vertCanvas->splitBarThickness(ISplitCanvas::splitBarMiddle);
- ysplit = horzCanvas->splitBarThickness(ISplitCanvas::splitBarEdge)*2 +
- horzCanvas->splitBarThickness(ISplitCanvas::splitBarMiddle);
- // ITRACE_DEVELOP("splitbarthickness(edge) = " +
- // IString(vertCanvas->splitBarThickness(ISplitCanvas::splitBarEdge)) +
- // " splitbarthickness(middle) = " +
- // IString(vertCanvas->splitBarThickness(ISplitCanvas::splitBarMiddle)));
- // vertCanvas->setSplitWindowPercentage(boardWindow, boardWindow->pixelSize());
- // vertCanvas->setSplitWindowPercentage(buttCanvas, 120);
- // vertCanvas->setSplitWindowPercentage(statCanvas, (odx-8) - boardWindow->pixelSize() - 120 - xsplit*2);
-
- horzCanvas->setSplitWindowPercentage(vertCanvas, boardWindow->pixelSize());
- horzCanvas->setSplitWindowPercentage(commWindow, (ody-56) - boardWindow->pixelSize() - ysplit*1);
- // vertCanvas->refresh();
- horzCanvas->refresh();
-
- /**************************************************************
- * setup menubar
- **************************************************************/
- menuBar=new IMenuBar(WND_PMICS, this); //Create the information area
- menuBar->checkItem(MI_BOARD_LOCK);
- menuBar->checkItem(MI_PROMOTION_Q);
- ITrace::isTraceEnabled() ? menuBar->checkItem(MI_TRACE) :
- menuBar->uncheckItem(MI_TRACE);
- if (getIntOption("autoflag", 0))
- menuBar->checkItem(MI_AUTOFLAG);
- if (stringOption("bs") == "del") {
- menuBar->checkItem(MI_BS2DEL);
- commWindow->bs2del = true;
- }
- else
- commWindow->bs2del = false;
- if (stringOption("cr") == "lf") {
- menuBar->checkItem(MI_CR2LF);
- commWindow->cr2lf = true;
- }
- else
- commWindow->cr2lf = false;
- if (intOption("localecho")) {
- menuBar->checkItem(MI_LOCAL_ECHO);
- commWindow->localecho = true;
- }
- else
- commWindow->localecho = false;
-
- /**************************************************************
- * setup help on the menubar
- **************************************************************/
- helpSettings
- .setTitle("PMICS help")
- .setLibraries("PMICS.HLP");
- helpWindow = new IHelpWindow(helpSettings);
- helpWindow->associateWindow(this);
- helpHdr = new HelpCommandHandler;
- helpHdr->handleEventsFor(this);
-
- /*********************************************************************
- * handlers and timers
- *********************************************************************/
- handleEventsFor(this);
- msgHandler = new PmicsMsgHandler(this);
- msgHandler->handleEventsFor(this);
- WinStartTimer((HAB)IThread::current().anchorBlock(), // 1 second timer
- (HWND)handle(),
- 1,
- 1000); // tick every second
-
- commWindow->setFocus(); // Set focus to the main window
- show(); // Show the main window
-
- ITRACE_DEVELOP("wpmics: window sizes");
- ITRACE_DEVELOP(" pmicsWindow: " + size().asString());
- ITRACE_DEVELOP(" boardWindow: " + boardWindow->size().asString());
- ITRACE_DEVELOP(" horzCanvas: " + horzCanvas->size().asString());
- ITRACE_DEVELOP(" vertCanvas: " + vertCanvas->size().asString());
- ITRACE_DEVELOP(" statCanvas: " + statCanvas->size().asString());
- ITRACE_DEVELOP(" buttCanvas: " + buttCanvas->size().asString());
- ITRACE_DEVELOP(" commWindow: " + commWindow->size().asString());
- } /* end PmicsWindow :: PmicsWindow(...) */
-
-
- /**************************************************************************
- * FUNCTION: setupStat (class PmicsWindow)
- *
- * DESCRIPTION: Create stat window. Has text controls for player names,
- * countdown clocks, game number and last move. Has pushbuttons for
- * common ICS commands that don't require parameters (e.g. resign, flag).
- * MultiCellCanvas is used to arrange these items.
- **************************************************************************/
- void PmicsWindow :: setupStat (IWindow *parent)
- {
- int numPushbuttons;
-
- IFUNCTRACE_DEVELOP();
-
- /* kludge: reduce the number of pushbuttons for -small geometry */
- /* so the button column is smaller than the board window. */
- /* otherwise the comm window is forced to shrink. */
- numPushbuttons = (boardWindow->pixelSize() > 320 ?
- NUM_PUSHBUTTONS : 8);
-
- statCanvas = new IMultiCellCanvas(WND_STAT, parent, parent);
-
- buttCanvas = new ISetCanvas(WND_BUTT, parent, parent);
- buttCanvas->setDeckOrientation( ISetCanvas::vertical )
- .setPackType( ISetCanvas::expanded )
- .setAlignment( ISetCanvas::topLeft )
- .setPad(ISize(5,5)); // width,height
-
- for (int bnum = 0; bnum<numPushbuttons; bnum++) {
- pushButton[bnum] = new IPushButton(WND_BUTTON_BASE+bnum,
- buttCanvas, buttCanvas);
- pushButton[bnum]->setText(buttonInfo[bnum].label);
- pushButton[bnum]->disableMouseClickFocus();
-
- if (buttonInfo[bnum].flags & BUTTONINFO_FL_RED) {
- pushButton[bnum]->setColor(IButton::border, IColor(IColor::red));
- pushButton[bnum]->setColor(IButton::foreground, IColor(IColor::red));
- pushButton[bnum]->setColor(IButton::disabledForeground, IColor(IColor::red));
- }
- }
-
- textWName = new ISetCanvas(WND_WNAME, statCanvas, statCanvas);
- textWName->setText("white");
-
- textWClock = new IStaticText(WND_WCLOCK, textWName, textWName);
- textWClock->setFont(IFont("Helvetica",18));
- textWClock->setLimit(5); // allocate room for 5 chars
- statWClock = 3600;
-
- textBName = new ISetCanvas(WND_BNAME, statCanvas, statCanvas);
- textBName->setText("black");
-
- textBClock = new IStaticText(WND_BCLOCK, textBName, textBName);
- textBClock->setFont(IFont("Helvetica",18));
- textBClock->setLimit(5); // allocate room for 5 chars
- statBClock = 3600;
- tickClock = NULL;
- updateClocks();
-
- textGameName = new IStaticText(WND_GAME_NAME, statCanvas, statCanvas);
- textGameName->setText("Game 0");
-
- textMove = new IStaticText(WND_MOVE, statCanvas, statCanvas);
- textMove->setText("o-o-o");
-
-
- /* for (bnum=0; bnum<numPushbuttons; bnum++) {
- buttCanvas->addToCell(pushButton[bnum], 1,bnum+1);
- }*/
- statCanvas->addToCell(textWName, 2,2);
- statCanvas->addToCell(textBName, 2,4);
- statCanvas->addToCell(textGameName,2,6);
- statCanvas->addToCell(textMove, 2,7);
- statCanvas->setColumnWidth(1,10); // left margin
- statCanvas->setRowHeight(1,10); // top margin
- }
-
-
- void PmicsWindow::statWhiteTop()
- {
- IFUNCTRACE_DEVELOP();
- statCanvas->removeFromCell(textWName);
- statCanvas->removeFromCell(textBName);
-
- statCanvas->addToCell(textWName, 2,2);
- statCanvas->addToCell(textBName, 2,4);
- statCanvas->refresh();
- }
-
- void PmicsWindow::statWhiteBottom()
- {
- IFUNCTRACE_DEVELOP();
- statCanvas->removeFromCell(textWName);
- statCanvas->removeFromCell(textBName);
-
- statCanvas->addToCell(textWName, 2,4);
- statCanvas->addToCell(textBName, 2,2);
- statCanvas->refresh();
- }
-
- void PmicsWindow::updateStat(char *p_)
- {
- struct statData {
- char onMove;
- int wClock, bClock, gameNum;
- char wName[32], bName[32], move[32];
- } *p = (struct statData *)(p_);
-
- // in addition to displaying the chess clocks, save off the times in
- // private data. the timer tick continuously updates the clocks
- // every second.
- statWClock = p->wClock;
- statBClock = p->bClock;
- tickClock = NULL;
- updateClocks();
- tickClock = (p->onMove == 'W' ? &statWClock : &statBClock);
-
- if (textWName->text() != p->wName)
- textWName->setText(p->wName);
- if (textBName->text() != p->bName)
- textBName->setText(p->bName);
- if (textGameName->text() != "Game " + IString(p->gameNum))
- textGameName->setText("Game " + IString(p->gameNum));
- gameNum = p->gameNum; // save off for Moves button
- textMove->setText(p->move);
- }
-
- void PmicsWindow::updateClocks()
- {
- char wTextClock[20], bTextClock[20];
- if (tickClock != NULL) {
- (*tickClock) --;
-
- if (onMove == -1 && // opponent's move
- (*tickClock == 0 || *tickClock == -1) &&
- menuBar->isItemChecked(MI_AUTOFLAG)) {
- aSession->write("flag");
- aSession->write(IString(commWindow->crChar()));
- }
- }
-
- sprintf(wTextClock, "%d:%02d ", statWClock/60, statWClock % 60);
- sprintf(bTextClock, "%d:%02d ", statBClock/60, statBClock % 60);
- textWClock->setText(wTextClock);
- textBClock->setText(bTextClock);
- }
-
- void PmicsWindow::statWhiteOnMove(unsigned int whoseMove)
- {
- IColor color = (whoseMove==1)? IColor::red : IColor::green;
- onMove = whoseMove;
- textWClock->setColor(IStaticText::background, color);
- /* textBName->setColor(IStaticText::background,
- statCanvas->color(ISetCanvas::background));*/
- textBClock->setColor(IStaticText::background, statCanvas->color());
- }
-
- void PmicsWindow::statBlackOnMove(unsigned int whoseMove)
- {
- IColor color = (whoseMove==1) ? IColor::red : IColor::green;
- onMove = whoseMove;
- textBClock->setColor(IStaticText::background, color);
- /*textWName->setColor(IStaticText::background,
- statCanvas->color(ISetCanvas::background));*/
- textWClock->setColor(IStaticText::background, statCanvas->color());
- }
-
-
- /**************************************************************************
- * FUNCTION: dispatchHandlerEvent (class PmicsMsgHandler)
- *
- * DESCRIPTION: IEvent (window message) handler for PmicsWindow.
- **************************************************************************/
- Boolean PmicsMsgHandler::dispatchHandlerEvent(IEvent &evt)
- {
- static Boolean whiteAtTop = false;
- PmicsWindow *pmicsWindow = (PmicsWindow *)evt.window();
-
- switch (evt.eventId()) {
- case MSG_STAT_UPDATE:
- {
- char *p;
- ITRACE_DEVELOP("MSG_STAT_UPDATE received");
- p = (char *)IEventData(evt.parameter1());
- pmicsWindow->updateStat(p);
- free((void *)p);
- break;
- }
- case MSG_STAT_WHITE_AT_TOP:
- ITRACE_DEVELOP("MSG_STAT_WHITE_AT_TOP received");
- pmicsWindow->statWhiteTop();
- whiteAtTop = true;
- break;
- case MSG_STAT_WHITE_AT_BOTTOM:
- ITRACE_DEVELOP("MSG_STAT_WHITE_AT_BOTTOM received");
- pmicsWindow->statWhiteBottom();
- whiteAtTop = false;
- break;
- case MSG_STAT_WHITE_AT_OTHER:
- ITRACE_DEVELOP("MSG_STAT_WHITE_AT_OTHER received");
- if (whiteAtTop = 1 - whiteAtTop)
- pmicsWindow->statWhiteTop();
- else
- pmicsWindow->statWhiteBottom();
- break;
- case MSG_STAT_WHITE_ONMOVE:
- pmicsWindow->statWhiteOnMove(IEventData(evt.parameter1()));
- break;
- case MSG_STAT_BLACK_ONMOVE:
- pmicsWindow->statBlackOnMove(IEventData(evt.parameter1()));
- break;
- case WM_TIMER:
- pmicsWindow->updateClocks();
- pmicsWindow->commWindow->timerTick();
- break;
- default:
- return false;
- }
- return true;
- }
-
-
- IString PmicsWindow :: expandButtonAction(IString in)
- {
- IString out;
- int inLen = in.size();
- for (int i=1; i<=inLen; i++) {
- if (in[i] != '%' || i == inLen)
- out += in[i];
- else {
- i++;
- switch (in[i]) {
- case 'g':
- out += gameNum;
- break;
- default:
- out += "%";
- break;
- }
- }
- }
- return out;
- }
-
- /**************************************************************************
- * FUNCTION: command (class PmicsWindow)
- *
- * DESCRIPTION: ICommandEvent (menu bar) handler for PmicsWindow.
- **************************************************************************/
-
- Boolean PmicsWindow :: command(ICommandEvent &cmdEvent)
- {
- IResourceLibrary reslib;
-
- IFUNCTRACE_DEVELOP();
- switch (cmdEvent.commandId()) {
- case MI_QUIT:
- postEvent(WM_CLOSE);
- break;
- case MI_FLIP:
- hBoard.postEvent(MSG_BOARD_FLIP);
- break;
- case MI_BOARD_LOCK:
- if (menuBar->isItemChecked(MI_BOARD_LOCK))
- menuBar->uncheckItem(MI_BOARD_LOCK);
- else
- menuBar->checkItem(MI_BOARD_LOCK);
- break;
- case MI_BOARD_REPLOT:
- hBoard.postEvent(MSG_BOARD_REPLOT);
- break;
- case MI_NEWBOARD:
- AGame::current()->initialize();
- hBoard.postEvent(MSG_BOARD_WHITE_AT_BOTTOM);
- break;
- case MI_FONT:
- hComm.postEvent(MSG_COM_FONT);
- break;
- case MI_TRACE:
- ITrace::isTraceEnabled() ? ITrace::disableTrace() : ITrace::enableTrace();
- ITrace::isTraceEnabled() ? menuBar->checkItem(MI_TRACE) :
- menuBar->uncheckItem(MI_TRACE);
- break;
- case MI_AUTOFLAG:
- if (menuBar->isItemChecked(MI_AUTOFLAG)) {
- menuBar->uncheckItem(MI_AUTOFLAG);
- }
- else {
- menuBar->checkItem(MI_AUTOFLAG);
- }
- break;
- case MI_LOCAL_ECHO:
- if (menuBar->isItemChecked(MI_LOCAL_ECHO)) {
- menuBar->uncheckItem(MI_LOCAL_ECHO);
- commWindow->localecho = false;
- }
- else {
- menuBar->checkItem(MI_LOCAL_ECHO);
- commWindow->localecho = true;
- }
- break;
- case MI_BS2DEL:
- if (menuBar->isItemChecked(MI_BS2DEL)) {
- menuBar->uncheckItem(MI_BS2DEL);
- commWindow->bs2del = false;
- }
- else {
- menuBar->checkItem(MI_BS2DEL);
- commWindow->bs2del = true;
- }
- break;
- case MI_CR2LF:
- if (menuBar->isItemChecked(MI_CR2LF)) {
- menuBar->uncheckItem(MI_CR2LF);
- commWindow->cr2lf = false;
- }
- else {
- menuBar->checkItem(MI_CR2LF);
- commWindow->cr2lf = true;
- }
- break;
- case MI_PROMOTION_Q:
- hBoard.postEvent(MI_PROMOTION_Q);
- menuBar->checkItem(MI_PROMOTION_Q);
- menuBar->uncheckItem(MI_PROMOTION_R);
- menuBar->uncheckItem(MI_PROMOTION_B);
- menuBar->uncheckItem(MI_PROMOTION_N);
- break;
- case MI_PROMOTION_R:
- hBoard.postEvent(MI_PROMOTION_R);
- menuBar->checkItem(MI_PROMOTION_R);
- menuBar->uncheckItem(MI_PROMOTION_Q);
- menuBar->uncheckItem(MI_PROMOTION_B);
- menuBar->uncheckItem(MI_PROMOTION_N);
- break;
- case MI_PROMOTION_B:
- hBoard.postEvent(MI_PROMOTION_B);
- menuBar->checkItem(MI_PROMOTION_B);
- menuBar->uncheckItem(MI_PROMOTION_Q);
- menuBar->uncheckItem(MI_PROMOTION_R);
- menuBar->uncheckItem(MI_PROMOTION_N);
- break;
- case MI_PROMOTION_N:
- hBoard.postEvent(MI_PROMOTION_N);
- menuBar->checkItem(MI_PROMOTION_N);
- menuBar->uncheckItem(MI_PROMOTION_Q);
- menuBar->uncheckItem(MI_PROMOTION_R);
- menuBar->uncheckItem(MI_PROMOTION_B);
- break;
-
- default:
- if (cmdEvent.commandId() < WND_BUTTON_BASE ||
- cmdEvent.commandId() >= WND_BUTTON_BASE+11)
- return false;
- aSession->write(expandButtonAction(buttonInfo[cmdEvent.commandId() - WND_BUTTON_BASE].action) + IString(commWindow->crChar()));
- }
- return true;
- }
-
-
- /**************************************************************************
- * FUNCTION: command (class HelpCommandHandler)
- *
- * DESCRIPTION: Process help menu-bar selections
- **************************************************************************/
-
- Boolean HelpCommandHandler :: command(ICommandEvent &evt)
- {
- IFUNCTRACE_DEVELOP();
- switch (evt.commandId()) {
- case MI_PRODUCTINFO:
- {
- IMessageBox mb(evt.window());
- mb.setTitle("Product Information")
- .show(
- "PMICS, a graphical ICS client for OS/2 PM\n"
- "Copyright (C) 1994 Kevin Nomura\n"
- "\n"
- "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,\n"
- "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
- "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
- "GNU General Public License for more details.\n"
- "Author can be reached at email: chow@netcom.com\n",
- IMessageBox::informationIcon |
- IMessageBox::okButton);
- return true;
- }
- case MI_HELPINDEX:
- {
- helpWindow->show(IHelpWindow::index);
- return true;
- }
- case MI_HELPINDEX2:
- {
- IHelpWindow *help = IHelpWindow::helpWindow(evt.window());
- help->show(IHelpWindow::index);
- return true;
- }
- }
- return false;
- }
-