1 //------------------------------------------------------------------------------
2 // XSilChess.cpp - X11 version of SilChess
3 //
4 // Copyright (C) 2001-2005,2007-2009 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <Xm/XmAll.h>
26 #include <X11/IntrinsicP.h>
27 #include <SilChess/SilChessRayTracer.h>
28
29
30 //==============================================================================
31 //============================== XSilChessWindow ===============================
32 //==============================================================================
33
34 class XSilChessWindow {
35
36 public:
37
38 XSilChessWindow(XtAppContext app, Widget toplevel, Visual * vsl,
39 int vsldepth, Colormap cmap);
40
41 ~XSilChessWindow();
42
43 private:
44
45 static void HandleCallback(Widget widget, XtPointer client_data,
46 XtPointer call_data);
47
48 static void HandleEvent(Widget widget, XtPointer data,
49 XEvent * event, Boolean *);
50
51 void HandleCallbackOrEvent(Widget widget,
52 XmAnyCallbackStruct * cbs,
53 XEvent * event);
54
55 void MousePress(int x, int y);
56
57 void DoSearching();
58
59 void UpdateStatusBar();
60
61 void UpdateMovesList();
62
63 void UpdateView();
64
65 void UpdateDepthMenu();
66
67 void DoPainting();
68
69 void PaintSel();
70
71 SilChessMachine * Machine;
72 int SelX,SelY;
73 char OverwriteFile[1024];
74
75 bool IsSearching,AbortSearching;
76 bool NeedPainting,IsPainting;
77 bool HintWanted,HintValid;
78 SilChessMachine::Move Hint;
79
80 XtAppContext App;
81 Display * Disp;
82 Visual * Vsl, * DlgVsl;
83 int VslDepth, DlgVslDepth;
84 Colormap CMap, DlgCMap;
85 int PixelSize,RedMask,GreenMask,BlueMask;
86 Widget TopLevel,MainWin,MainMenu,
87 FileMenu,BFileLoad,BFileSave,BFileExit,BFile,
88 GameMenu,BGameNew,BGameFlip,BGameUndo,BGameList,BGame,
89 DepthMenu,BDepth[SilChessMachine::MAX_SEARCH_DEPTH+1],
90 CompMenu,BCompHint,BCompDepth,BComp,HelpMenu,BHelp,
91 BHelpAbout,MainForm,StatusFrame,StatusLabel,ViewFrame,
92 ViewArea,LoadDialog,SaveDialog,OverwriteDialog,ErrorBox,
93 ListDialogPopup,ListDialog,LDClose,LDScroll,LDList,
94 AboutDialog;
95 Dimension ViewWidth,ViewHeight;
96 Window ViewWin;
97 GC ViewGC;
98 SilChessRayTracer RT;
99
100 static const char * const AboutText;
101 };
102
103
XSilChessWindow(XtAppContext app,Widget toplevel,Visual * vsl,int vsldepth,Colormap cmap)104 XSilChessWindow::XSilChessWindow(XtAppContext app, Widget toplevel,
105 Visual * vsl, int vsldepth, Colormap cmap)
106 {
107 char tmp[512];
108 Arg al[10];
109 int i;
110 XmString xms;
111
112 // Initialize member variables
113 App=app;
114 TopLevel=toplevel;
115 Disp=XtDisplay(TopLevel);
116 Vsl=vsl;
117 VslDepth=vsldepth;
118 CMap=cmap;
119 DlgVsl=DefaultVisual(Disp,XScreenNumberOfScreen(XtScreen(TopLevel)));
120 DlgVslDepth=DefaultDepth(Disp,XScreenNumberOfScreen(XtScreen(TopLevel)));
121 DlgCMap=DefaultColormap(Disp,XScreenNumberOfScreen(XtScreen(TopLevel)));
122 PixelSize=(VslDepth<=8 ? 1 : (VslDepth<=16 ? 2 : 4));
123 RedMask=Vsl->red_mask;
124 GreenMask=Vsl->green_mask;
125 BlueMask=Vsl->blue_mask;
126 SelX=SelY-1;
127 IsSearching=false;
128 AbortSearching=false;
129 NeedPainting=false;
130 IsPainting=false;
131 HintWanted=false;
132 HintValid=false;
133
134 // Create main window
135 MainWin=XtVaCreateManagedWidget(
136 "mainWin",xmMainWindowWidgetClass,TopLevel,
137 (char*)NULL
138 );
139
140 // Create main menu bar
141 MainMenu=XmCreateMenuBar(MainWin,(char*)"mainMenu",NULL,0);
142 XtManageChild(MainMenu);
143
144 // Create menu item: file
145 XtSetArg(al[0],XmNvisual,Vsl);
146 XtSetArg(al[1],XmNdepth,VslDepth);
147 XtSetArg(al[2],XmNcolormap,CMap);
148 FileMenu=XmCreatePulldownMenu(MainMenu,(char*)"fileMenu",al,3);
149 BFile=XtVaCreateManagedWidget(
150 "file",xmCascadeButtonWidgetClass,MainMenu,
151 XmNsubMenuId,FileMenu,
152 (char*)NULL
153 );
154
155 // Create menu item: file/load
156 BFileLoad=XtVaCreateManagedWidget(
157 "load",xmPushButtonWidgetClass,FileMenu,
158 (char*)NULL
159 );
160 XtAddCallback(BFileLoad,XmNactivateCallback,HandleCallback,this);
161
162 // Create menu item: file/save
163 BFileSave=XtVaCreateManagedWidget(
164 "save",xmPushButtonWidgetClass,FileMenu,
165 (char*)NULL
166 );
167 XtAddCallback(BFileSave,XmNactivateCallback,HandleCallback,this);
168
169 // Create menu item: file/exit
170 XtVaCreateManagedWidget(
171 "separator",xmSeparatorWidgetClass,FileMenu,
172 (char*)NULL
173 );
174 BFileExit=XtVaCreateManagedWidget(
175 "exit",xmPushButtonWidgetClass,FileMenu,
176 (char*)NULL
177 );
178 XtAddCallback(BFileExit,XmNactivateCallback,HandleCallback,this);
179
180 // Create menu item: game
181 XtSetArg(al[0],XmNvisual,Vsl);
182 XtSetArg(al[1],XmNdepth,VslDepth);
183 XtSetArg(al[2],XmNcolormap,CMap);
184 GameMenu=XmCreatePulldownMenu(MainMenu,(char*)"gameMenu",al,3);
185 BGame=XtVaCreateManagedWidget(
186 "game",xmCascadeButtonWidgetClass,MainMenu,
187 XmNsubMenuId,GameMenu,
188 (char*)NULL
189 );
190
191 // Create menu item: game/new
192 BGameNew=XtVaCreateManagedWidget(
193 "new",xmPushButtonWidgetClass,GameMenu,
194 (char*)NULL
195 );
196 XtAddCallback(BGameNew,XmNactivateCallback,HandleCallback,this);
197
198 // Create menu item: game/flip
199 BGameFlip=XtVaCreateManagedWidget(
200 "flip",xmPushButtonWidgetClass,GameMenu,
201 (char*)NULL
202 );
203 XtAddCallback(BGameFlip,XmNactivateCallback,HandleCallback,this);
204
205 // Create menu item: game/undo
206 BGameUndo=XtVaCreateManagedWidget(
207 "undo",xmPushButtonWidgetClass,GameMenu,
208 (char*)NULL
209 );
210 XtAddCallback(BGameUndo,XmNactivateCallback,HandleCallback,this);
211
212 // Create menu item: game/list
213 BGameList=XtVaCreateManagedWidget(
214 "list",xmPushButtonWidgetClass,GameMenu,
215 (char*)NULL
216 );
217 XtAddCallback(BGameList,XmNactivateCallback,HandleCallback,this);
218
219 // Create menu item: computer
220 XtSetArg(al[0],XmNvisual,Vsl);
221 XtSetArg(al[1],XmNdepth,VslDepth);
222 XtSetArg(al[2],XmNcolormap,CMap);
223 CompMenu=XmCreatePulldownMenu(MainMenu,(char*)"compMenu",al,3);
224 BComp=XtVaCreateManagedWidget(
225 "comp",xmCascadeButtonWidgetClass,MainMenu,
226 XmNsubMenuId,CompMenu,
227 (char*)NULL
228 );
229
230 // Create menu item: computer/hint
231 BCompHint=XtVaCreateManagedWidget(
232 "hint",xmPushButtonWidgetClass,CompMenu,
233 (char*)NULL
234 );
235 XtAddCallback(BCompHint,XmNactivateCallback,HandleCallback,this);
236
237 // Create menu item: computer/depth
238 XtSetArg(al[0],XmNvisual,Vsl);
239 XtSetArg(al[1],XmNdepth,VslDepth);
240 XtSetArg(al[2],XmNcolormap,CMap);
241 XtSetArg(al[3],XmNradioBehavior,True);
242 DepthMenu=XmCreatePulldownMenu(CompMenu,(char*)"depthMenu",al,4);
243 BCompDepth=XtVaCreateManagedWidget(
244 "depth",xmCascadeButtonWidgetClass,CompMenu,
245 XmNsubMenuId,DepthMenu,
246 (char*)NULL
247 );
248
249 // Create menu items: computer/depth/1...
250 for (i=0; i<=SilChessMachine::MAX_SEARCH_DEPTH; i++) {
251 sprintf(tmp,"%d",i);
252 BDepth[i]=XtVaCreateManagedWidget(
253 tmp,xmToggleButtonWidgetClass,DepthMenu,
254 (char*)NULL
255 );
256 XtAddCallback(BDepth[i],XmNvalueChangedCallback,HandleCallback,this);
257 }
258
259 // Create menu item: help
260 XtSetArg(al[0],XmNvisual,Vsl);
261 XtSetArg(al[1],XmNdepth,VslDepth);
262 XtSetArg(al[2],XmNcolormap,CMap);
263 HelpMenu=XmCreatePulldownMenu(MainMenu,(char*)"helpMenu",al,3);
264 BHelp=XtVaCreateManagedWidget(
265 "help",xmCascadeButtonWidgetClass,MainMenu,
266 XmNsubMenuId,HelpMenu,
267 (char*)NULL
268 );
269 XtVaSetValues(MainMenu,XmNmenuHelpWidget,BHelp,(char*)NULL);
270
271 // Create menu item: help/about
272 BHelpAbout=XtVaCreateManagedWidget(
273 "about",xmPushButtonWidgetClass,HelpMenu,
274 (char*)NULL
275 );
276 XtAddCallback(BHelpAbout,XmNactivateCallback,HandleCallback,this);
277
278 // Create a parent for status bar and view
279 MainForm=XtVaCreateManagedWidget(
280 "mainForm",xmFormWidgetClass,MainWin,
281 (char*)NULL
282 );
283
284 // Create status line
285 StatusFrame=XtVaCreateManagedWidget(
286 "statusFrame",xmFrameWidgetClass,MainForm,
287 XmNleftAttachment,XmATTACH_FORM,
288 XmNrightAttachment,XmATTACH_FORM,
289 XmNtopAttachment,XmATTACH_FORM,
290 (char*)NULL
291 );
292 StatusLabel=XtVaCreateManagedWidget(
293 "statusLabel",xmLabelWidgetClass,StatusFrame,
294 XmNalignment, XmALIGNMENT_BEGINNING,
295 (char*)NULL
296 );
297
298 // Create the chess board view
299 ViewFrame=XtVaCreateManagedWidget(
300 "viewFrame",xmFrameWidgetClass,MainForm,
301 XmNtopAttachment,XmATTACH_WIDGET,
302 XmNtopWidget,StatusFrame,
303 XmNleftAttachment,XmATTACH_FORM,
304 XmNrightAttachment,XmATTACH_FORM,
305 XmNbottomAttachment,XmATTACH_FORM,
306 (char*)NULL
307 );
308 ViewArea=XtVaCreateManagedWidget(
309 "viewArea",xmDrawingAreaWidgetClass,ViewFrame,
310 XmNtopAttachment,XmATTACH_FORM,
311 XmNleftAttachment,XmATTACH_FORM,
312 XmNrightAttachment,XmATTACH_FORM,
313 XmNbottomAttachment,XmATTACH_FORM,
314 (char*)NULL
315 );
316 XtAddCallback(ViewArea,XmNexposeCallback,HandleCallback,this);
317 XtAddCallback(ViewArea,XmNresizeCallback,HandleCallback,this);
318 XtAddEventHandler(
319 ViewArea,ButtonPressMask|ButtonMotionMask|ButtonReleaseMask|
320 StructureNotifyMask,False,HandleEvent,this
321 );
322 XtVaGetValues(ViewArea,XmNwidth,&ViewWidth,(char*)NULL);
323 XtVaGetValues(ViewArea,XmNheight,&ViewHeight,(char*)NULL);
324 ViewWin=0;
325 ViewGC=NULL;
326
327 // Create dialog: load game
328 XtSetArg(al[0],XmNvisual,DlgVsl);
329 XtSetArg(al[1],XmNdepth,DlgVslDepth);
330 XtSetArg(al[2],XmNcolormap,DlgCMap);
331 XtSetArg(al[3],XmNautoUnmanage,True);
332 LoadDialog=XmCreateFileSelectionDialog(TopLevel,(char*)"loadDialog",al,4);
333 XtAddCallback(LoadDialog,XmNokCallback,HandleCallback,this);
334 XtUnmanageChild(XmFileSelectionBoxGetChild(LoadDialog,XmDIALOG_HELP_BUTTON));
335
336 // Create dialog: save game
337 XtSetArg(al[0],XmNvisual,DlgVsl);
338 XtSetArg(al[1],XmNdepth,DlgVslDepth);
339 XtSetArg(al[2],XmNcolormap,DlgCMap);
340 XtSetArg(al[3],XmNautoUnmanage, True);
341 SaveDialog=XmCreateFileSelectionDialog(TopLevel,(char*)"saveDialog",al,4);
342 XtAddCallback(SaveDialog,XmNokCallback,HandleCallback,this);
343 XtUnmanageChild(XmFileSelectionBoxGetChild(SaveDialog,XmDIALOG_HELP_BUTTON));
344
345 // Create dialog: file exists, overwrite?
346 XtSetArg(al[0],XmNvisual,DlgVsl);
347 XtSetArg(al[1],XmNdepth,DlgVslDepth);
348 XtSetArg(al[2],XmNcolormap,DlgCMap);
349 XtSetArg(al[3],XmNautoUnmanage, True);
350 OverwriteDialog=XmCreateWarningDialog(TopLevel,(char*)"overwriteDialog",al,4);
351 XtUnmanageChild(XmMessageBoxGetChild(OverwriteDialog,XmDIALOG_HELP_BUTTON));
352 XtAddCallback(OverwriteDialog,XmNokCallback,HandleCallback,this);
353
354 // Create dialog: error message
355 XtSetArg(al[0],XmNvisual,DlgVsl);
356 XtSetArg(al[1],XmNdepth,DlgVslDepth);
357 XtSetArg(al[2],XmNcolormap,DlgCMap);
358 XtSetArg(al[3],XmNautoUnmanage, True);
359 ErrorBox=XmCreateWarningDialog(TopLevel,(char*)"errorBox",al,4);
360 XtUnmanageChild(XmMessageBoxGetChild(ErrorBox,XmDIALOG_CANCEL_BUTTON));
361 XtUnmanageChild(XmMessageBoxGetChild(ErrorBox,XmDIALOG_HELP_BUTTON));
362
363 // Create dialog: list of moves
364 ListDialogPopup=XtVaCreateWidget(
365 "listDialog_popup",xmDialogShellWidgetClass,TopLevel,
366 XmNvisual,DlgVsl,
367 XmNdepth,DlgVslDepth,
368 XmNcolormap,DlgCMap,
369 (char*)NULL
370 );
371 ListDialog=XtVaCreateWidget(
372 "listDialog",xmFormWidgetClass,ListDialogPopup,
373 (char*)NULL
374 );
375 LDClose=XtVaCreateManagedWidget(
376 "close",xmPushButtonWidgetClass,ListDialog,
377 XmNleftAttachment,XmATTACH_FORM,
378 XmNrightAttachment,XmATTACH_FORM,
379 XmNbottomAttachment,XmATTACH_FORM,
380 (char*)NULL
381 );
382 XtAddCallback(LDClose,XmNactivateCallback,HandleCallback,this);
383 LDScroll=XtVaCreateManagedWidget(
384 "scroll",xmScrolledWindowWidgetClass,ListDialog,
385 XmNscrollingPolicy,XmAUTOMATIC,
386 XmNscrollBarDisplayPolicy,XmAS_NEEDED,
387 XmNleftAttachment,XmATTACH_FORM,
388 XmNrightAttachment,XmATTACH_FORM,
389 XmNtopAttachment,XmATTACH_FORM,
390 XmNbottomAttachment,XmATTACH_WIDGET,
391 XmNbottomWidget,LDClose,
392 (char*)NULL
393 );
394 LDList=XtVaCreateManagedWidget(
395 "list",xmLabelGadgetClass,LDScroll,
396 XmNalignment,XmALIGNMENT_BEGINNING,
397 (char*)NULL
398 );
399
400 // Create dialog: about
401 xms=XmStringCreateLtoR((char*)AboutText,XmFONTLIST_DEFAULT_TAG);
402 XtSetArg(al[0],XmNvisual,DlgVsl);
403 XtSetArg(al[1],XmNdepth,DlgVslDepth);
404 XtSetArg(al[2],XmNcolormap,DlgCMap);
405 XtSetArg(al[3],XmNautoUnmanage,True);
406 XtSetArg(al[4],XmNmessageString,xms);
407 XtSetArg(al[5],XmNmessageAlignment,XmALIGNMENT_CENTER);
408 AboutDialog=XmCreateMessageDialog(TopLevel,(char*)"aboutDialog",al,6);
409 XmStringFree(xms);
410 XtUnmanageChild(XmMessageBoxGetChild(AboutDialog,XmDIALOG_CANCEL_BUTTON));
411 XtUnmanageChild(XmMessageBoxGetChild(AboutDialog,XmDIALOG_HELP_BUTTON));
412
413 // Set main window areas
414 XmMainWindowSetAreas(MainWin,MainMenu,NULL,NULL,NULL,MainForm);
415
416 // Create chess machine
417 Machine = new SilChessMachine();
418
419 // Setup ray tracer
420 RT.SetViewSize(ViewWidth,ViewHeight);
421 RT.SetWorld(Machine);
422
423 // Update all
424 UpdateStatusBar();
425 UpdateMovesList();
426 UpdateView();
427 UpdateDepthMenu();
428 }
429
430
~XSilChessWindow()431 XSilChessWindow::~XSilChessWindow()
432 {
433 delete Machine;
434 }
435
436
HandleCallback(Widget widget,XtPointer client_data,XtPointer call_data)437 void XSilChessWindow::HandleCallback(Widget widget, XtPointer client_data,
438 XtPointer call_data)
439 {
440 ((XSilChessWindow*)client_data)->HandleCallbackOrEvent(
441 widget,
442 (XmAnyCallbackStruct*)call_data,
443 NULL
444 );
445 }
446
447
HandleEvent(Widget widget,XtPointer data,XEvent * event,Boolean *)448 void XSilChessWindow::HandleEvent(Widget widget, XtPointer data,
449 XEvent * event, Boolean *)
450 {
451 ((XSilChessWindow*)data)->HandleCallbackOrEvent(
452 widget,
453 NULL,
454 event
455 );
456 }
457
458
HandleCallbackOrEvent(Widget widget,XmAnyCallbackStruct * cbs,XEvent * event)459 void XSilChessWindow::HandleCallbackOrEvent(Widget widget,
460 XmAnyCallbackStruct * cbs,
461 XEvent * event)
462 {
463 XGCValues gcval;
464 const char * file_name;
465 XmString xms;
466 char tmp[512];
467 int i;
468
469 if (widget==BFileLoad) {
470 XtUnmanageChild(LoadDialog);
471 XmFileSelectionDoSearch(LoadDialog,NULL);
472 XtManageChild(LoadDialog);
473 }
474 else if (widget==BFileSave) {
475 XtUnmanageChild(SaveDialog);
476 XmFileSelectionDoSearch(SaveDialog,NULL);
477 XtManageChild(SaveDialog);
478 }
479 else if (widget==BFileExit) {
480 exit(0);
481 }
482 else if (widget==BGameNew) {
483 AbortSearching=true;
484 HintWanted=false;
485 HintValid=false;
486 Machine->StartNewGame();
487 RT.SetWorld(Machine);
488 UpdateStatusBar();
489 UpdateMovesList();
490 UpdateView();
491 }
492 else if (widget==BGameFlip) {
493 AbortSearching=true;
494 HintWanted=false;
495 HintValid=false;
496 Machine->SetHumanWhite(!Machine->IsHumanWhite());
497 RT.SetWorld(Machine);
498 UpdateStatusBar();
499 UpdateView();
500 }
501 else if (widget==BGameUndo) {
502 AbortSearching=true;
503 HintWanted=false;
504 HintValid=false;
505 Machine->UndoMove();
506 if (!Machine->IsHumanOn()) Machine->UndoMove();
507 RT.SetWorld(Machine);
508 UpdateStatusBar();
509 UpdateMovesList();
510 UpdateView();
511 }
512 else if (widget==BGameList) {
513 XtUnmanageChild(ListDialog);
514 XtManageChild(ListDialog);
515 }
516 else if (widget==LoadDialog) {
517 AbortSearching=true;
518 HintWanted=false;
519 HintValid=false;
520 file_name=XmTextGetString(
521 XmFileSelectionBoxGetChild(widget,XmDIALOG_TEXT)
522 );
523 if (!Machine->Load(file_name)) {
524 XtUnmanageChild(ErrorBox);
525 sprintf(tmp,"Failed to load '%s'",file_name);
526 xms=XmStringCreateSimple(tmp);
527 XtVaSetValues(ErrorBox,XmNmessageString,xms,(char*)NULL);
528 XmStringFree(xms);
529 XtManageChild(ErrorBox);
530 }
531 RT.SetWorld(Machine);
532 UpdateStatusBar();
533 UpdateMovesList();
534 UpdateView();
535 UpdateDepthMenu();
536 }
537 else if (widget==SaveDialog) {
538 file_name=XmTextGetString(
539 XmFileSelectionBoxGetChild(widget,XmDIALOG_TEXT)
540 );
541 if (access(file_name,F_OK)!=-1) {
542 XtUnmanageChild(OverwriteDialog);
543 sprintf(tmp,"OK to overwrite '%s'?",file_name);
544 xms=XmStringCreateSimple(tmp);
545 XtVaSetValues(OverwriteDialog,XmNmessageString,xms,(char*)NULL);
546 XmStringFree(xms);
547 XtManageChild(OverwriteDialog);
548 strcpy(OverwriteFile,file_name);
549 }
550 else if (!Machine->Save(file_name)) {
551 XtUnmanageChild(ErrorBox);
552 sprintf(tmp,"Failed to save '%s'",file_name);
553 xms=XmStringCreateSimple(tmp);
554 XtVaSetValues(ErrorBox,XmNmessageString,xms,(char*)NULL);
555 XmStringFree(xms);
556 XtManageChild(ErrorBox);
557 }
558 }
559 else if (widget==OverwriteDialog) {
560 file_name=OverwriteFile;
561 if (!Machine->Save(file_name)) {
562 XtUnmanageChild(ErrorBox);
563 sprintf(tmp,"Failed to save '%s'",file_name);
564 xms=XmStringCreateSimple(tmp);
565 XtVaSetValues(ErrorBox,XmNmessageString,xms,(char*)NULL);
566 XmStringFree(xms);
567 XtManageChild(ErrorBox);
568 }
569 }
570 else if (widget==ViewArea) {
571 if (cbs!=NULL && cbs->reason==XmCR_EXPOSE &&
572 cbs->event && cbs->event->xexpose.count==0) {
573 UpdateView();
574 }
575 else if (cbs!=NULL && cbs->reason==XmCR_RESIZE) {
576 XtVaGetValues(ViewArea,XmNwidth,&ViewWidth,(char*)NULL);
577 XtVaGetValues(ViewArea,XmNheight,&ViewHeight,(char*)NULL);
578 RT.SetViewSize(ViewWidth,ViewHeight);
579 UpdateView();
580 }
581 else if (event!=NULL && event->type==ButtonPress) {
582 MousePress(event->xbutton.x,event->xbutton.y);
583 }
584 else if (event!=NULL && event->type==MapNotify && !ViewWin) {
585 ViewWin=XtWindow(ViewArea);
586 ViewGC=XtGetGC(ViewArea,0,&gcval);
587 }
588 }
589 else if (widget==BCompHint) {
590 AbortSearching=true;
591 HintWanted=true;
592 HintValid=false;
593 UpdateStatusBar();
594 }
595 else if (widget==BHelpAbout) {
596 XtUnmanageChild(AboutDialog);
597 XtManageChild(AboutDialog);
598 }
599 else if (widget==LDClose) {
600 XtUnmanageChild(ListDialog);
601 }
602 else {
603 for (i=0; i<=SilChessMachine::MAX_SEARCH_DEPTH; i++) {
604 if (widget==BDepth[i] && cbs!=NULL) {
605 if (((XmToggleButtonCallbackStruct*)cbs)->set) {
606 AbortSearching=true;
607 Machine->SetSearchDepth(i);
608 UpdateStatusBar();
609 }
610 }
611 }
612 }
613 do {
614 DoPainting();
615 DoSearching();
616 } while(NeedPainting && !IsPainting && ViewWin);
617 }
618
619
MousePress(int x,int y)620 void XSilChessWindow::MousePress(int x, int y)
621 {
622 int i;
623 SilChessMachine::Move m;
624
625 RT.View2Board(x,y,&x,&y);
626 if (x<0 || y<0 || x>7 || y>7 || (x==SelX && y==SelY)) {
627 if (SelX!=-1 || SelY!=-1) {
628 SelX=SelY=-1;
629 UpdateView();
630 }
631 return;
632 }
633 i=Machine->GetField(x,y);
634 if (i!=0 && ((i<7) == Machine->IsWhiteOn())) {
635 if (SelX!=x || SelY!=y) {
636 if (SelX==-1 || SelY==-1) {
637 SelX=x;
638 SelY=y;
639 PaintSel();
640 }
641 else {
642 SelX=x;
643 SelY=y;
644 UpdateView();
645 }
646 }
647 return;
648 }
649 if (SelX!=-1 && SelY!=-1) {
650 m.X1=SelX;
651 m.Y1=SelY;
652 m.X2=x;
653 m.Y2=y;
654 if (Machine->IsLegalMove(m)) {
655 AbortSearching=true;
656 HintWanted=false;
657 HintValid=false;
658 Machine->DoMove(m);
659 SelX=SelY=-1;
660 RT.SetWorld(Machine);
661 UpdateStatusBar();
662 UpdateMovesList();
663 UpdateView();
664 }
665 else {
666 SelX=SelY=-1;
667 UpdateStatusBar();
668 UpdateView();
669 }
670 }
671 }
672
673
DoSearching()674 void XSilChessWindow::DoSearching()
675 {
676 XEvent e;
677 SilChessMachine::Move m;
678 bool res;
679
680 if (IsPainting) return;
681 if (IsSearching) return;
682 IsSearching=true;
683 while ((!Machine->IsHumanOn() || HintWanted) &&
684 !Machine->IsMate() && !Machine->IsDraw() && !Machine->IsEndless()) {
685 AbortSearching=false;
686 Machine->StartSearching();
687 for (;;) {
688 if (Machine->ContinueSearching()) break;
689 while (XtAppPending(App)) {
690 XtAppNextEvent(App,&e);
691 XtDispatchEvent(&e);
692 }
693 if (AbortSearching) break;
694 }
695 res=Machine->EndSearching(&m);
696 if (!AbortSearching && res) {
697 if (!Machine->IsHumanOn()) {
698 Machine->DoMove(m);
699 RT.SetWorld(Machine);
700 UpdateStatusBar();
701 UpdateMovesList();
702 UpdateView();
703 }
704 else if (HintWanted) {
705 HintWanted=false;
706 Hint=m;
707 HintValid=true;
708 UpdateStatusBar();
709 }
710 }
711 }
712 IsSearching=false;
713 }
714
715
UpdateStatusBar()716 void XSilChessWindow::UpdateStatusBar()
717 {
718 XmString xms;
719 char tmp[512];
720
721 tmp[0]=0;
722 if (Machine->GetMoveCount()>0) {
723 Machine->GetMove(Machine->GetMoveCount()-1).ToString(tmp+strlen(tmp));
724 sprintf(tmp+strlen(tmp)," <%d> ",Machine->GetValue());
725 }
726 if (Machine->IsMate()) strcat(tmp,"MATE!");
727 else if (Machine->IsDraw()) strcat(tmp,"DRAW!");
728 else if (Machine->IsEndless()) strcat(tmp,"ENDLESS!");
729 else {
730 if (Machine->IsCheck()) strcat(tmp,"check! ");
731 if (!Machine->IsHumanOn()) {
732 sprintf(tmp+strlen(tmp),"searching (%d)...",Machine->GetSearchDepth());
733 }
734 else if (HintWanted) {
735 sprintf(tmp+strlen(tmp),"searching hint (%d)...",Machine->GetSearchDepth());
736 }
737 else {
738 if (HintValid) {
739 strcat(tmp,"hint: ");
740 Hint.ToString(tmp+strlen(tmp));
741 strcat(tmp,", ");
742 }
743 strcat(tmp,"your move? ");
744 }
745 }
746 xms=XmStringCreateLtoR(tmp,XmFONTLIST_DEFAULT_TAG);
747 XtVaSetValues(StatusLabel,XmNlabelString,xms,(char*)NULL);
748 XmStringFree(xms);
749 }
750
751
UpdateMovesList()752 void XSilChessWindow::UpdateMovesList()
753 {
754 XmString xms;
755 Widget clpwin,scrbar;
756 char * buf, * p;
757 int i,smax,ssiz;
758 Position x,y;
759 Dimension h,hc;
760
761 buf=(char*)malloc(65536);
762 p=buf;
763 for (i=0; i<Machine->GetMoveCount(); i++) {
764 if ((i&1)==0) p+=sprintf(p,"%03d",i/2+1);
765 *p++=' ';
766 Machine->GetMove(i).ToString(p);
767 p+=4;
768 if ((i&1)!=0 || i==Machine->GetMoveCount()-1) *p++='\n';
769 }
770 *p=0;
771 if (p==buf) strcpy(buf,"<empty>");
772 xms=XmStringCreateLtoR(buf,XmFONTLIST_DEFAULT_TAG);
773 free(buf);
774
775 XtVaSetValues(LDList,XmNlabelString,xms,(char*)NULL);
776 XmStringFree(xms);
777
778 // Make last entry visible
779 clpwin=NULL;
780 XtVaGetValues(LDScroll,XmNclipWindow,&clpwin,(char*)NULL);
781 if (clpwin) {
782 XtVaGetValues(LDList,XmNx,&x,XmNy,&y,XmNheight,&h,(char*)NULL);
783 XtVaGetValues(clpwin,XmNheight,&hc,(char*)NULL);
784 if (((Position)hc-h)<y) {
785 XtMoveWidget(LDList,x,hc-h);
786 scrbar=NULL;
787 XtVaGetValues(LDScroll,XmNverticalScrollBar,&scrbar,(char*)NULL);
788 if (scrbar) {
789 XtVaGetValues(scrbar,XmNmaximum,&smax,XmNsliderSize,&ssiz,(char*)NULL);
790 XtVaSetValues(scrbar,XmNvalue,smax-ssiz,(char*)NULL);
791 }
792 }
793 }
794 }
795
796
UpdateView()797 void XSilChessWindow::UpdateView()
798 {
799 NeedPainting=true;
800 }
801
802
UpdateDepthMenu()803 void XSilChessWindow::UpdateDepthMenu()
804 {
805 int i;
806
807 for (i=0; i<SilChessMachine::MAX_SEARCH_DEPTH; i++) {
808 XtVaSetValues(
809 BDepth[i],
810 XmNset,
811 Machine->GetSearchDepth()==i ? True : False,
812 (char*)NULL
813 );
814 }
815 }
816
817
DoPainting()818 void XSilChessWindow::DoPainting()
819 {
820 XEvent e;
821 char * data;
822 XImage * img;
823 int i,y,msk;
824
825 if (IsPainting) return;
826 if (!ViewWin) return;
827 IsPainting=true;
828 y=0;
829 while (NeedPainting) {
830 NeedPainting=false;
831 RT.SetWorld(Machine);
832 data=(char*)malloc(PixelSize*ViewWidth+1000000);
833 img=XCreateImage(Disp,Vsl,VslDepth,ZPixmap,0,data,
834 ViewWidth,1,8*PixelSize,0);
835 for (msk=0x3ff; msk<ViewHeight-1; msk=(msk<<1)|1);
836 for (i=0, y%=ViewHeight; i<ViewHeight; i++) {
837 while (XtAppPending(App)!=0) {
838 XtAppNextEvent(App,&e);
839 XtDispatchEvent(&e);
840 }
841 if (NeedPainting) break;
842 RT.RenderScanline(y,data,PixelSize,RedMask,GreenMask,BlueMask);
843 XPutImage(Disp,ViewWin,ViewGC,img,0,0,0,y,ViewWidth,1);
844 if (i==ViewHeight-1 || (i&7)==0) PaintSel();
845 do { y=(y+269779)&msk; } while (y>=ViewHeight);
846 }
847 PaintSel();
848 XFree(img);
849 free(data);
850 }
851 IsPainting=false;
852 }
853
854
PaintSel()855 void XSilChessWindow::PaintSel()
856 {
857 int i,tx,ty;
858 int mvx[4],mvy[4];
859
860 if (SelX<0 || SelY<0 || !ViewWin) return;
861 RT.Board2View(SelX-0.5,SelY-0.5,&(mvx[0]),&(mvy[0]));
862 RT.Board2View(SelX-0.5,SelY+0.5,&(mvx[1]),&(mvy[1]));
863 RT.Board2View(SelX+0.5,SelY+0.5,&(mvx[2]),&(mvy[2]));
864 RT.Board2View(SelX+0.5,SelY-0.5,&(mvx[3]),&(mvy[3]));
865 XSetForeground(Disp,ViewGC,0);
866 for (i=0; i<4; i++) {
867 tx=mvx[(i+1)&3]+(mvx[i]-mvx[(i+1)&3])/6;
868 ty=mvy[(i+1)&3]+(mvy[i]-mvy[(i+1)&3])/6;
869 XDrawLine(Disp,ViewWin,ViewGC,tx,ty,mvx[(i+1)&3],mvy[(i+1)&3]);
870 tx=mvx[i]+(mvx[(i+1)&3]-mvx[i])/6;
871 ty=mvy[i]+(mvy[(i+1)&3]-mvy[i])/6;
872 XDrawLine(Disp,ViewWin,ViewGC,mvx[i],mvy[i],tx,ty);
873 }
874 }
875
876
877 const char * const XSilChessWindow::AboutText=
878 "XSilChess 3.1\n\n"
879 "Copyright (C) 2001-2009 Oliver Hamann\n"
880 ;
881
882
883 //==============================================================================
884 //============================= SCDefaultResources =============================
885 //==============================================================================
886
887 static const char * SCDefaultResources[]= {
888 "XSilChess*.background: #c0c0c0",
889 "XSilChess*.foreground: black",
890 "XSilChess.title: XSilChess",
891 "XSilChess.minWidth: 190",
892 "XSilChess.minHeight: 176",
893 "XSilChess.mainWin.width: 460",
894 "XSilChess.mainWin.height: 350",
895 "XSilChess.mainWin.mainMenu.shadowThickness: 1",
896 "XSilChess.mainWin.mainMenu.file.labelString: File",
897 "XSilChess.mainWin.mainMenu.file.mnemonic: F",
898 "XSilChess.mainWin.mainMenu*.fileMenu.load.labelString: Load...",
899 "XSilChess.mainWin.mainMenu*.fileMenu.load.mnemonic: L",
900 "XSilChess.mainWin.mainMenu*.fileMenu.load.accelerator: Ctrl<Key>L",
901 "XSilChess.mainWin.mainMenu*.fileMenu.load.acceleratorText: Ctrl+L",
902 "XSilChess.mainWin.mainMenu*.fileMenu.save.labelString: Save...",
903 "XSilChess.mainWin.mainMenu*.fileMenu.save.mnemonic: S",
904 "XSilChess.mainWin.mainMenu*.fileMenu.save.accelerator: Ctrl<Key>S",
905 "XSilChess.mainWin.mainMenu*.fileMenu.save.acceleratorText: Ctrl+S",
906 "XSilChess.mainWin.mainMenu*.fileMenu.exit.labelString: Exit",
907 "XSilChess.mainWin.mainMenu*.fileMenu.exit.mnemonic: x",
908 "XSilChess.mainWin.mainMenu*.fileMenu.exit.accelerator: Ctrl<Key>Q",
909 "XSilChess.mainWin.mainMenu*.fileMenu.exit.acceleratorText: Ctrl+Q",
910 "XSilChess.mainWin.mainMenu.game.labelString: Game",
911 "XSilChess.mainWin.mainMenu.game.mnemonic: G",
912 "XSilChess.mainWin.mainMenu*.gameMenu.new.labelString: New Game",
913 "XSilChess.mainWin.mainMenu*.gameMenu.new.mnemonic: N",
914 "XSilChess.mainWin.mainMenu*.gameMenu.new.accelerator: Ctrl<Key>N",
915 "XSilChess.mainWin.mainMenu*.gameMenu.new.acceleratorText: Ctrl+N",
916 "XSilChess.mainWin.mainMenu*.gameMenu.flip.labelString: Flip Sides",
917 "XSilChess.mainWin.mainMenu*.gameMenu.flip.mnemonic: F",
918 "XSilChess.mainWin.mainMenu*.gameMenu.flip.accelerator: Ctrl<Key>F",
919 "XSilChess.mainWin.mainMenu*.gameMenu.flip.acceleratorText: Ctrl+F",
920 "XSilChess.mainWin.mainMenu*.gameMenu.undo.labelString: Undo Move",
921 "XSilChess.mainWin.mainMenu*.gameMenu.undo.mnemonic: U",
922 "XSilChess.mainWin.mainMenu*.gameMenu.undo.accelerator: Ctrl<Key>Z",
923 "XSilChess.mainWin.mainMenu*.gameMenu.undo.acceleratorText: Ctrl+Z",
924 "XSilChess.mainWin.mainMenu*.gameMenu.list.labelString: Show Moves...",
925 "XSilChess.mainWin.mainMenu*.gameMenu.list.mnemonic: M",
926 "XSilChess.mainWin.mainMenu*.gameMenu.list.accelerator: Ctrl<Key>M",
927 "XSilChess.mainWin.mainMenu*.gameMenu.list.acceleratorText: Ctrl+M",
928 "XSilChess.mainWin.mainMenu.comp.labelString: Computer",
929 "XSilChess.mainWin.mainMenu.comp.mnemonic: C",
930 "XSilChess.mainWin.mainMenu*.compMenu.hint.labelString: Give Hint",
931 "XSilChess.mainWin.mainMenu*.compMenu.hint.mnemonic: H",
932 "XSilChess.mainWin.mainMenu*.compMenu.hint.accelerator: Ctrl<Key>H",
933 "XSilChess.mainWin.mainMenu*.compMenu.hint.acceleratorText: Ctrl+H",
934 "XSilChess.mainWin.mainMenu*.compMenu.depth.labelString: Search Depth",
935 "XSilChess.mainWin.mainMenu*.compMenu.depth.mnemonic: D",
936 "XSilChess.mainWin.mainMenu.help.labelString: Help",
937 "XSilChess.mainWin.mainMenu.help.mnemonic: H",
938 "XSilChess.mainWin.mainMenu*.helpMenu.about.labelString: About...",
939 "XSilChess.mainWin.mainMenu*.helpMenu.about.mnemonic: A",
940 "XSilChess.mainWin.mainForm.statusFrame.shadowType: SHADOW_IN",
941 "XSilChess.mainWin.mainForm.statusFrame.shadowThickness: 1",
942 "XSilChess.mainWin.mainForm.viewFrame.shadowType: SHADOW_IN",
943 "XSilChess.mainWin.mainForm.viewFrame.shadowThickness: 0",
944 "XSilChess.mainWin.mainForm.viewFrame.viewArea.background: #4d3319",
945 "XSilChess.loadDialog_popup.loadDialog.dialogTitle: Load Game",
946 "XSilChess.loadDialog_popup.loadDialog.pattern: *.silchess",
947 "XSilChess.saveDialog_popup.saveDialog.dialogTitle: Save Game",
948 "XSilChess.saveDialog_popup.saveDialog.pattern: *.silchess",
949 "XSilChess.overwriteDialog_popup.overwriteDialog.dialogTitle: File exists",
950 "XSilChess.errorBox_popup.errorBox.dialogTitle: Error",
951 "XSilChess.listDialog_popup.title: List of Moves",
952 "XSilChess.listDialog_popup.minWidth: 96",
953 "XSilChess.listDialog_popup.minHeight: 96",
954 "XSilChess.listDialog_popup.listDialog.close.labelString: Close",
955 "XSilChess.aboutDialog_popup.aboutDialog.dialogTitle: About",
956 NULL
957 };
958
959
960 //==============================================================================
961 //==================================== main ====================================
962 //==============================================================================
963
main(int argc,char * argv[])964 int main(int argc, char * argv[])
965 {
966 XtAppContext App;
967 XSilChessWindow * MainWindow;
968 Widget TopLevel;
969 Colormap colormap;
970 Visual * visual;
971 XVisualInfo * vil;
972 XVisualInfo vit;
973 Display * display;
974 int vic,i,depth;
975
976 TopLevel=XtVaAppInitialize(
977 &App,"XSilChess",NULL,0,&argc,argv,
978 (char**)SCDefaultResources,(char*)NULL
979 );
980 display=XtDisplay(TopLevel);
981 memset(&vit,0,sizeof(vit));
982 vit.screen=XScreenNumberOfScreen(XtScreen(TopLevel));
983 vil=XGetVisualInfo(display,VisualScreenMask,&vit,&vic);
984 visual=NULL;
985 depth=0;
986 for (i=0; i<vic; i++) {
987 if (vil[i].c_class==TrueColor) {
988 visual=vil[i].visual;
989 depth=vil[i].depth;
990 break;
991 }
992 }
993 if (visual==NULL) {
994 fprintf(stderr,"ERROR: no true color visual available\n");
995 return 1;
996 }
997 colormap=XCreateColormap(display,DefaultRootWindow(display),visual,AllocNone);
998 XtVaSetValues(
999 TopLevel,
1000 XmNvisual,visual,
1001 XmNdepth,depth,
1002 XmNcolormap,colormap,
1003 (char*)NULL
1004 );
1005 MainWindow=new XSilChessWindow(App,TopLevel,visual,depth,colormap);
1006 XtRealizeWidget(TopLevel);
1007 XtAppMainLoop(App);
1008 delete MainWindow;
1009 return 0;
1010 }
1011