first take on reszing the windows
[xboard.git] / callback.c
1 #include <gtk/gtk.h>
2 #include "common.h"
3 #include "xboard.h"
4 #include <errno.h>
5 #include "backend.h"
6
7 #ifdef ENABLE_NLS
8 # define  _(s) gettext (s)
9 # define N_(s) gettext_noop (s)
10 #else
11 # define  _(s) (s)
12 # define N_(s)  s
13 #endif
14
15 extern GtkWidget  *about;
16 extern GtkWidget  *GUI_Window;
17 extern GtkWidget  *GUI_Menubar;
18 extern GtkWidget  *GUI_Timer;
19 extern GtkWidget  *GUI_Buttonbar;
20 extern GtkWidget  *GUI_Board;
21
22 extern char *programVersion;
23 extern int errorExitStatus;
24 extern int promotionUp;
25 extern int fromX;
26 extern int fromY;
27 extern int toX;
28 extern int toY;
29 extern int squareSize,lineGap;
30
31 gboolean
32 ExposeProc(object, user_data)
33      GtkObject *object;
34      gpointer user_data;
35 {
36   /* do resizing to a fixed aspect ratio */
37   GtkRequisition w;
38   int totalh=0,nw,nh;
39   float ratio;
40   int boardWidth,boardHeight,old,new;
41   
42   nw=GTK_WIDGET(object)->allocation.width;
43   nh=GTK_WIDGET(object)->allocation.height;
44     
45   old=squareSize;
46   squareSize  = nw/(BOARD_WIDTH*1.05+0.05);
47
48   if(old!=squareSize)
49     {
50       lineGap = squareSize*0.05;
51       
52       boardWidth  = lineGap + BOARD_WIDTH  * (squareSize + lineGap);
53       boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
54       
55       /* get the height of the menus, etc. and calculate the aspect ratio */
56       gtk_widget_size_request(GTK_WIDGET(GUI_Menubar),   &w);
57       totalh += w.height;
58       gtk_widget_size_request(GTK_WIDGET(GUI_Timer),   &w);
59       totalh += w.height;
60       gtk_widget_size_request(GTK_WIDGET(GUI_Buttonbar),   &w);
61       totalh += w.height;
62       
63       ratio  = (totalh+boardHeight)/(boardWidth) ;
64             
65       gtk_widget_set_size_request(GTK_WIDGET(GUI_Board),
66                                   boardWidth,boardHeight);
67       
68       GUI_SetAspectRatio(ratio);
69       /* recreate pieces with new size... TODO: keep svg in memory and just recreate pixmap instead of reloading files */
70       CreatePieces();
71     } 
72   return FALSE; /* return false, so that other expose events are called too */
73 }
74
75 void
76 QuitProc (object, user_data)
77      GtkObject *object;
78      gpointer user_data;
79 {
80   gtk_main_quit();
81   ExitEvent(0);
82 }
83
84 /* Help Menu */
85 void InfoProc(object, user_data)
86      GtkObject *object;
87      gpointer user_data;
88 {
89     char buf[MSG_SIZ];
90     snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
91             INFODIR, INFOFILE);
92     system(buf);
93     return;
94 }
95
96 void ManProc(object, user_data)
97      GtkObject *object;
98      gpointer user_data;
99 {
100     char buf[MSG_SIZ];
101     snprintf(buf, sizeof(buf), "xterm -e man xboard &");
102     system(buf);
103     return;
104 }
105
106 void HintProc(object, user_data)
107      GtkObject *object;
108      gpointer user_data;
109 {
110     HintEvent();
111     return;
112 }
113
114 void BookProc(object, user_data)
115      GtkObject *object;
116      gpointer user_data;
117 {
118     BookEvent();
119     return;
120 }
121
122 void AboutProc (object, user_data)
123      GtkObject *object;
124      gpointer user_data;
125 {
126   GtkWidget               *about;
127
128   const gchar *authors[] = {"Tim Mann <tim@tim-mann.org>",
129                             "John Chanak",
130                             "Evan Welsh <Evan.Welsh@msdw.com>",
131                             "Elmar Bartel <bartel@informatik.tu-muenchen.de>",
132                             "Jochen Wiedmann",
133                             "Frank McIngvale",
134                             "Hugh Fisher <Hugh.Fisher@cs.anu.edu.au>",
135                             "Allessandro Scotti",
136                             "H.G. Muller <h.g.muller AT hccnet DOT nl>",
137                             "Eric Mullins <emwine AT earthlink DOT net>",
138                             "Arun Persaud <arun@nubati.net>"};
139
140   /* set up about window */
141   about =  GTK_WIDGET(gtk_about_dialog_new());
142
143   /* fill in some information */
144   char buf[MSG_SIZ];
145 #if ZIPPY
146   char *zippy = " (with Zippy code)";
147 #else
148   char *zippy = "";
149 #endif
150   sprintf(buf, "%s%s",  programVersion, zippy);
151
152   gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),buf);
153
154   gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about),
155                                  "Copyright 1991 Digital Equipment Corporation\n"
156                                  "Enhancements Copyright 1992-2009 Free Software Foundation\n"
157                                  "Enhancements Copyright 2005 Alessandro Scotti");
158   gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),"http://www.gnu.org/software/xboard/");
159   gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about),authors);
160   gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about),
161                                           " A. Alper (turkish)\n"
162                                           " A. Persaud (german)\n");
163
164   /* end set up about window */
165   gtk_dialog_run(GTK_DIALOG (about));
166   gtk_widget_destroy(about);
167 }
168
169 /* End Help Menu */
170
171 void IcsClientProc(object, user_data)
172      GtkObject *object;
173      gpointer user_data;
174 {
175     IcsClientEvent();
176     return;
177 }
178
179 void LoadNextGameProc(object, user_data)
180      GtkObject *object;
181      gpointer user_data;
182 {
183     ReloadGame(1);
184     return;
185 }
186
187 void LoadPrevGameProc(object, user_data)
188      GtkObject *object;
189      gpointer user_data;
190 {
191     ReloadGame(-1);
192     return;
193 }
194
195 void ReloadGameProc(object, user_data)
196      GtkObject *object;
197      gpointer user_data;
198 {
199     ReloadGame(0);
200     return;
201 }
202
203 void MachineWhiteProc(object, user_data)
204      GtkObject *object;
205      gpointer user_data;
206 {
207     MachineWhiteEvent();
208     return;
209 }
210
211 void MachineBlackProc(object, user_data)
212      GtkObject *object;
213      gpointer user_data;
214 {
215     MachineBlackEvent();
216     return;
217 }
218
219 void TwoMachinesProc(object, user_data)
220      GtkObject *object;
221      gpointer user_data;
222 {
223     TwoMachinesEvent();
224     return;
225 }
226
227 void AcceptProc(object, user_data)
228      GtkObject *object;
229      gpointer user_data;
230 {
231     AcceptEvent();
232     return;
233 }
234
235 void DeclineProc(object, user_data)
236      GtkObject *object;
237      gpointer user_data;
238 {
239     DeclineEvent();
240     return;
241 }
242
243 void RematchProc(object, user_data)
244      GtkObject *object;
245      gpointer user_data;
246 {
247     RematchEvent();
248     return;
249 }
250
251 void CallFlagProc(object, user_data)
252      GtkObject *object;
253      gpointer user_data;
254 {
255     CallFlagEvent();
256     return;
257 }
258
259 void DrawProc(object, user_data)
260      GtkObject *object;
261      gpointer user_data;
262 {
263     DrawEvent();
264     return;
265 }
266
267 void AbortProc(object, user_data)
268      GtkObject *object;
269      gpointer user_data;
270 {
271     AbortEvent();
272     return;
273 }
274
275 void AdjournProc(object, user_data)
276      GtkObject *object;
277      gpointer user_data;
278 {
279     AdjournEvent();
280     return;
281 }
282
283 void ResignProc(object, user_data)
284      GtkObject *object;
285      gpointer user_data;
286 {
287     ResignEvent();
288     return;
289 }
290
291 void StopObservingProc(object, user_data)
292      GtkObject *object;
293      gpointer user_data;
294 {
295     StopObservingEvent();
296     return;
297 }
298
299 void StopExaminingProc(object, user_data)
300      GtkObject *object;
301      gpointer user_data;
302 {
303     StopExaminingEvent();
304     return;
305 }
306
307 void AdjuWhiteProc(object, user_data)
308      GtkObject *object;
309      gpointer user_data;
310 {
311     UserAdjudicationEvent(+1);
312     return;
313 }
314
315 void AdjuBlackProc(object, user_data)
316      GtkObject *object;
317      gpointer user_data;
318 {
319     UserAdjudicationEvent(-1);
320     return;
321 }
322
323 void AdjuDrawProc(object, user_data)
324      GtkObject *object;
325      gpointer user_data;
326 {
327     UserAdjudicationEvent(0);
328     return;
329 }
330
331 void BackwardProc(object, user_data)
332      GtkObject *object;
333      gpointer user_data;
334 {
335     BackwardEvent();
336     return;
337 }
338
339 void ForwardProc(object, user_data)
340      GtkObject *object;
341      gpointer user_data;
342 {
343     ForwardEvent();
344     return;
345 }
346
347 void ToStartProc(object, user_data)
348      GtkObject *object;
349      gpointer user_data;
350 {
351     ToStartEvent();
352     return;
353 }
354
355 void ToEndProc(object, user_data)
356      GtkObject *object;
357      gpointer user_data;
358 {
359     ToEndEvent();
360     return;
361 }
362
363 void RevertProc(object, user_data)
364      GtkObject *object;
365      gpointer user_data;
366 {
367     RevertEvent();
368     return;
369 }
370
371 void TruncateGameProc(object, user_data)
372      GtkObject *object;
373      gpointer user_data;
374 {
375     TruncateGameEvent();
376     return;
377 }
378
379 void MoveNowProc(object, user_data)
380      GtkObject *object;
381      gpointer user_data;
382 {
383     MoveNowEvent();
384     return;
385 }
386
387 void RetractMoveProc(object, user_data)
388      GtkObject *object;
389      gpointer user_data;
390 {
391     RetractMoveEvent();
392     return;
393 }
394
395 /* Option Menu */
396 void ShowThinkingProc(object, user_data)
397      GtkObject *object;
398      gpointer user_data;
399 {
400     appData.showThinking = !appData.showThinking; 
401     ShowThinkingEvent();
402
403     return;
404 }
405
406 void HideThinkingProc(object, user_data)
407      GtkObject *object;
408      gpointer user_data;
409 {
410     appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman;
411     ShowThinkingEvent();
412
413     return;
414 }
415
416 void FlipViewProc(object, user_data)
417      GtkObject *object;
418      gpointer user_data;
419 {
420     flipView = !flipView;
421     DrawPosition(True, NULL);
422     return;
423 }
424
425
426 gboolean CloseWindowProc(GtkWidget *button)
427 {
428     gtk_widget_destroy(gtk_widget_get_toplevel(button));
429     return TRUE;
430 }
431
432 void
433 ResetProc (object, user_data)
434      GtkObject *object;
435      gpointer user_data;
436 {
437   ResetGameEvent();
438   AnalysisPopDown();
439 }
440
441 void WhiteClockProc(object, user_data)
442      GtkObject *object;
443      gpointer user_data;
444 {
445     if (gameMode == EditPosition || gameMode == IcsExamining) {
446         SetWhiteToPlayEvent();
447     } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
448         CallFlagEvent();
449     }
450 }
451
452 void BlackClockProc(object, user_data)
453      GtkObject *object;
454      gpointer user_data;
455 {
456     if (gameMode == EditPosition || gameMode == IcsExamining) {
457         SetBlackToPlayEvent();
458     } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
459         CallFlagEvent();
460     }
461 }
462
463
464 void ShowCoordsProc(object, user_data)
465      GtkObject *object;
466      gpointer user_data;
467 {
468     appData.showCoords = !appData.showCoords;
469
470     DrawPosition(True, NULL);
471 }
472
473 void ErrorPopDownProc(object, user_data)
474      GtkObject *object;
475      gpointer user_data;
476 {
477   gtk_widget_destroy(GTK_WIDGET(object));
478   ErrorPopDown();
479 }
480
481 void PauseProc(object, user_data)
482      GtkObject *object;
483      gpointer user_data;
484 {
485     // todo this toggling of the pause button doesn't seem to work?
486     // e.g. select pause from buttonbar doesn't activate menumode.pause
487   PauseEvent();
488 }
489
490
491 void LoadGameProc(object, user_data)
492      GtkObject *object;
493      gpointer user_data;
494 {
495   GtkWidget *dialog;
496   dialog = gtk_file_chooser_dialog_new (_("Load game file name?"),
497                                         GTK_WINDOW(GUI_Window),
498                                         GTK_FILE_CHOOSER_ACTION_OPEN,
499                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
500                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
501                                         NULL);
502   if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
503     {
504       char *filename;
505       FILE *f;
506
507       filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
508
509       //see loadgamepopup
510       f = fopen(filename, "rb");
511       if (f == NULL) 
512         {
513           DisplayError(_("Failed to open file"), errno);
514         }
515       else 
516         {
517           /* TODO add indec */
518           (void) LoadGamePopUp(f, 0, filename);
519         }
520       g_free (filename);
521     };
522   
523   gtk_widget_destroy (dialog);
524   ModeHighlight();
525   
526   return;
527 }
528
529
530 /*************
531  * EVENTS
532  *************/
533
534 void EventProc(window, event, data)
535      GtkWindow *window;
536      GdkEvent *event;
537      gpointer data;
538 {
539   /* todo do we still need this?
540     if (!XtIsRealized(widget))
541       return;
542   */
543
544     switch (event->type) {
545       case GDK_EXPOSE:
546         if (event->expose.count > 0) return;  /* no clipping is done */
547         DrawPosition(True, NULL);
548         break;
549       default:
550         return;
551     }
552 }
553
554
555 /*
556  * event handler for parsing user moves
557  */
558 void UserMoveProc(window, event, data)
559      GtkWindow *window;
560      GdkEvent *event;
561      gpointer data;
562 {
563     int x, y;
564     Boolean saveAnimate;
565     static int second = 0;
566
567     if (errorExitStatus != -1) return;
568
569     if (event->type == GDK_BUTTON_PRESS) ErrorPopDown();
570
571     if (promotionUp)
572       {
573         if (event->type == GDK_BUTTON_PRESS)
574           {
575             /* todo add promotionshellwidget
576                XtPopdown(promotionShell);
577                XtDestroyWidget(promotionShell); */
578             promotionUp = False;
579             ClearHighlights();
580             fromX = fromY = -1;
581           }
582         else
583           {
584             return;
585           }
586       }
587
588     x = EventToSquare( (int)event->button.x, BOARD_WIDTH  );
589     y = EventToSquare( (int)event->button.y, BOARD_HEIGHT );
590     if (!flipView && y >= 0)
591       {
592         y = BOARD_HEIGHT - 1 - y;
593       }
594     if (flipView && x >= 0)
595       {
596         x = BOARD_WIDTH - 1 - x;
597       }
598
599     if (fromX == -1)
600       {
601         if (event->type == ButtonPress)
602           {
603             /* First square */
604             if (OKToStartUserMove(x, y))
605               {
606                 fromX = x;
607                 fromY = y;
608                 second = 0;
609                 DragPieceBegin(event->button.x, event->button.y);
610                 if (appData.highlightDragging)
611                   {
612                     SetHighlights(x, y, -1, -1);
613                   }
614               }
615           }
616         return;
617       }
618
619     /* fromX != -1 */
620     if (event->type == GDK_BUTTON_PRESS && gameMode != EditPosition &&
621         x >= 0 && y >= 0) {
622         ChessSquare fromP;
623         ChessSquare toP;
624         /* Check if clicking again on the same color piece */
625         fromP = boards[currentMove][fromY][fromX];
626         toP = boards[currentMove][y][x];
627         if ((WhitePawn <= fromP && fromP <= WhiteKing &&
628              WhitePawn <= toP && toP <= WhiteKing) ||
629             (BlackPawn <= fromP && fromP <= BlackKing &&
630              BlackPawn <= toP && toP <= BlackKing)) {
631             /* Clicked again on same color piece -- changed his mind */
632             second = (x == fromX && y == fromY);
633             if (appData.highlightDragging) {
634                 SetHighlights(x, y, -1, -1);
635             } else {
636                 ClearHighlights();
637             }
638             if (OKToStartUserMove(x, y)) {
639                 fromX = x;
640                 fromY = y;
641                 DragPieceBegin(event->button.x, event->button.y);
642             }
643             return;
644         }
645     }
646
647     if (event->type == GDK_BUTTON_RELEASE &&    x == fromX && y == fromY)
648       {
649         DragPieceEnd(event->button.x, event->button.y);
650         if (appData.animateDragging)
651           {
652             /* Undo animation damage if any */
653             DrawPosition(FALSE, NULL);
654           }
655         if (second)
656           {
657             /* Second up/down in same square; just abort move */
658             second = 0;
659             fromX = fromY = -1;
660             ClearHighlights();
661             gotPremove = 0;
662             ClearPremoveHighlights();
663           }
664         else
665           {
666             /* First upclick in same square; start click-click mode */
667             SetHighlights(x, y, -1, -1);
668           }
669         return;
670       }
671
672     /* Completed move */
673     toX = x;
674     toY = y;
675     saveAnimate = appData.animate;
676
677     if (event->type == GDK_BUTTON_PRESS)
678       {
679         /* Finish clickclick move */
680         if (appData.animate || appData.highlightLastMove)
681           {
682             SetHighlights(fromX, fromY, toX, toY);
683           }
684         else
685           {
686             ClearHighlights();
687           }
688       }
689     else
690       {
691         /* Finish drag move */
692         if (appData.highlightLastMove)
693           {
694             SetHighlights(fromX, fromY, toX, toY);
695           }
696         else
697           {
698             ClearHighlights();
699           }
700         DragPieceEnd(event->button.x, event->button.y);
701         /* Don't animate move and drag both */
702         appData.animate = FALSE;
703       }
704
705     if (IsPromotion(fromX, fromY, toX, toY))
706       {
707         if (appData.alwaysPromoteToQueen)
708           {
709             UserMoveEvent(fromX, fromY, toX, toY, 'q');
710             if (!appData.highlightLastMove || gotPremove) ClearHighlights();
711             if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
712             fromX = fromY = -1;
713           }
714         else
715           {
716             SetHighlights(fromX, fromY, toX, toY);
717             PromotionPopUp();
718           }
719       }
720     else
721       {
722         UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
723
724         if (!appData.highlightLastMove || gotPremove) ClearHighlights();
725         if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
726         fromX = fromY = -1;
727       }
728
729     appData.animate = saveAnimate;
730     if (appData.animate || appData.animateDragging) {
731         /* Undo animation damage if needed */
732         DrawPosition(FALSE, NULL);
733     }
734
735     return;
736 }
737
738 void GetMoveListProc(object, user_data)
739      GtkObject *object;
740      gpointer user_data;
741 {
742   appData.getMoveList = !appData.getMoveList;
743   
744   if (appData.getMoveList) 
745     {
746       GetMoveListEvent();
747     } 
748
749   // gets set automatically? if we set it with set_active we end up in an endless loop switching between 0 and 1
750   //  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (object),(gboolean) appData.getMoveList );
751   
752   return;
753 }