home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Pier Shareware 6
/
The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso
/
035
/
pmics.zip
/
wpmics.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1994-12-13
|
21KB
|
617 lines
/*
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));
boardWindow = new BoardWindow (WND_BOARD, vertCanvas);
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)
{
IFUNCTRACE_DEVELOP();
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<NUM_PUSHBUTTONS; 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<NUM_PUSHBUTTONS; 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\n");
}
}
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) + "\n");
}
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;
}