1 /*
2  *   XFrisk - The classic board game for X
3  *   Copyright (C) 1993-1999 Elan Feingold (elan@aetherworks.com)
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  *   $Id: colorEdit.c,v 1.21 2000/01/22 22:11:35 morphy Exp $
20  *
21  *   $Log: colorEdit.c,v $
22  *   Revision 1.21  2000/01/22 22:11:35  morphy
23  *   Comment changes
24  *
25  *   Revision 1.20  2000/01/22 22:46:54  tony
26  *   now updates example image when color entered in text inputline
27  *
28  *   Revision 1.19  2000/01/18 18:55:02  morphy
29  *   Reordered parameters passed to XawScrollbarSetThumb
30  *
31  *   Revision 1.18  2000/01/16 18:49:29  tony
32  *   scrollbar still screwed
33  *
34  *   Revision 1.17  2000/01/12 19:33:26  tony
35  *   moving around, commenting, scrollbars,edit box still no good
36  *
37  *   Revision 1.16  2000/01/10 22:47:40  tony
38  *   made colorstuff more private to colormap.c, only scrollbars get set wrong, rest seems to work ok now
39  *
40  *   Revision 1.15  2000/01/10 00:19:56  tony
41  *   and one more
42  *
43  *   Revision 1.14  2000/01/10 00:01:44  tony
44  *   and more..
45  *
46  *   Revision 1.13  2000/01/09 22:44:12  morphy
47  *   Fixes and optimizations in example image drawing
48  *
49  *   Revision 1.12  2000/01/09 21:47:48  morphy
50  *   Moved drawing of example country image to separate function
51  *
52  *   Revision 1.11  2000/01/09 21:20:33  morphy
53  *   Merged in fix for example image background color
54  *
55  *   Revision 1.10  2000/01/09 21:55:10  tony
56  *   made iCountry static, little fix in scrollbars
57  *
58  *   Revision 1.9  2000/01/09 20:58:38  tony
59  *   some comment
60  *
61  *   Revision 1.8  2000/01/05 23:21:35  tony
62  *   changed CARD_ to CARDS_
63  *
64  *   Revision 1.7  2000/01/04 21:41:53  tony
65  *   removed redundant stuff for jokers
66  */
67 
68 /** \file Change color of player */
69 
70 #include <X11/X.h>
71 #include <X11/Intrinsic.h>
72 #include <X11/StringDefs.h>
73 #include <X11/Shell.h>
74 #include <X11/Xaw/Scrollbar.h>
75 #include <X11/Xaw/Form.h>
76 #include <X11/Xaw/Command.h>
77 #include <X11/Xaw/AsciiText.h>
78 
79 #include "colorEdit.h"
80 #include "dice.h"
81 #include "callbacks.h"
82 #include "colormap.h"
83 #include "client.h"
84 #include "utils.h"
85 #include "cards.h"
86 #include "riskgame.h"
87 #include "gui-vars.h"
88 #include "debug.h"
89 #include "riskgame.h"
90 #include "viewStats.h"
91 
92 
93 /* Local functions */
94 static void COLEDIT_Cancel(void);
95 static void COLEDIT_ScrollbarMoved(void);
96 static void COLEDIT_UpdateExampleImage(Int32 iColor);
97 
98 /* Action tables */
99 static XtActionsRec actionTable[] =
100 {
101   { "updateColor",      (XtActionProc)COLEDIT_UpdateColorWithInput },
102   { "colorEditCancel",  (XtActionProc)COLEDIT_Cancel },
103   { NULL, NULL }
104 };
105 
106 /* Widgets */
107 static Widget wColorEditShell;
108 static Widget wColorEditForm;
109 static Widget wColorEditLabel;
110 static Widget wRedScrollbar, wBlueScrollbar, wGreenScrollbar;
111 static Widget wSampleCountryForm;
112 static Widget wColorInputLabel, wColorInputText;
113 static Widget wColorOK, wColorCancel;
114 
115 /* Color editing related things */
116 #define COLOR_EDIT_OK           1
117 #define COLOR_EDIT_CANCEL       0
118 #define COLOR_EDIT_INPROGRESS  -1
119 
120 static Int32 iQueryResult = COLOR_EDIT_OK;
121 static Pixmap pixSampleImage;/**< sample image */
122 static XImage *pScaledSample;
123 Int32 iCountry;/**< index of country clicked on*/
124 Int32 iglobalColor;/**< index of color */
125 
126 
127 /**
128  * \b History:
129  * \arg 01.22.95  ESF  Created.
130  * \arg 01.24.95  ESF  Changed to get coordinates manually.
131  * \arg 01.25.95  ESF  Added check that the country was not empty.
132  * \arg 12.07.95  ESF  Fixed a bug -- don't allow editing of ocean.
133  */
COLEDIT_MapShiftClick(void)134 void COLEDIT_MapShiftClick(void)
135 {
136   Int32   iColor;
137   Int32   x, y, xRoot, yRoot;
138   UInt32  uiButtons;
139   Window  winDummy1, winDummy2;
140 
141   if (!XQueryPointer(hDisplay, hWindow, &winDummy1, &winDummy2,
142 		    &xRoot, &yRoot, &x, &y, &uiButtons))
143     {
144       /* Pointer has somehow left window */
145       return;
146     }
147 
148   /* Get the coordinates of the mouse */
149   iColor = XGetPixel(pMapImage, x, y);
150   iCountry = COLOR_ColorToCountry(iColor);
151 
152   /* See if there is a player on the country
153    * no idea why?
154    */
155   if (iCountry<0 || iCountry>=NUM_COUNTRIES ||
156       RISK_GetOwnerOfCountry(iCountry) == -1 ||
157       RISK_GetNumArmiesOfCountry(iCountry) == 0)
158     return;
159 
160   /* Edit this color */
161   COLEDIT_EditColor(iColor, TRUE);/* ok here */
162 }
163 
COLEDIT_Ok(void)164 void COLEDIT_Ok(void) { iQueryResult = COLOR_EDIT_OK; }
COLEDIT_Cancel(void)165 void COLEDIT_Cancel(void) { iQueryResult = COLOR_EDIT_CANCEL; }
166 
167 
168 /**
169  * Set scrollbars and text input box to given color
170  *
171  * \b History:
172  * \arg 01.22.95  ESF  Created.
173  * \arg 18.08.95  JC   Modified to call COLOR_GetColor.
174  * \arg 18.01.00  MSH  Reordered X..SetThumb parameters.
175  */
COLEDIT_InitDialogWithColor(Int32 iColorNum)176 void COLEDIT_InitDialogWithColor (Int32 iColorNum)
177 {
178   float  f;
179   UInt16 r, g, b;
180   char buf[256];
181 
182   COLOR_GetColor(iColorNum, &r, &g, &b);
183 
184   f = 1.0 - ((float)r)/65535.0;
185   XawScrollbarSetThumb(wRedScrollbar, f, 0.05);
186 
187   f = 1.0 - ((float)g)/65535.0;
188   XawScrollbarSetThumb(wGreenScrollbar, f, 0.05);
189 
190   f = 1.0 - ((float)b)/65535.0;
191   XawScrollbarSetThumb(wBlueScrollbar, f, 0.05);
192 
193   /* Display the name of the color */
194   snprintf(buf, sizeof(buf), "#%02x%02x%02x",
195 	  r/256, g/256, b/256);
196   XtVaSetValues(wColorInputText,
197 		XtNstring, buf,
198 		XtNinsertPosition, strlen(buf),
199 		NULL);
200 }
201 
202 
203 /**
204  * Build the X dialog structure. Called from gui.c
205  *
206  * \b History:
207  * \arg 01.21.95  ESF  Created.
208  */
COLEDIT_BuildDialog(void)209  void COLEDIT_BuildDialog(void)
210 {
211     Widget  wColorDummy;
212 
213   /* Add Actions */
214   XtAppAddActions(appContext, actionTable, XtNumber(actionTable));
215 
216   wColorEditShell = XtCreatePopupShell("wColorEditShell",
217 				       transientShellWidgetClass,
218 				       wToplevel, pVisualArgs, iVisualCount);
219   wColorEditForm = XtCreateManagedWidget("wColorEditForm", formWidgetClass,
220 					 wColorEditShell, NULL, 0);
221   /* The label for the dialog */
222   wColorEditLabel = XtCreateManagedWidget("wColorEditLabel", labelWidgetClass,
223 					  wColorEditForm, NULL, 0);
224 
225   /* The three (RGB) scrollbars */
226   wRedScrollbar = XtCreateManagedWidget("wRedScrollbar",
227 					scrollbarWidgetClass,
228 					wColorEditForm, NULL, 0);
229   XtAddCallback(wRedScrollbar, XtNjumpProc,
230 		(XtCallbackProc)COLEDIT_ScrollbarMoved, NULL);
231   XawScrollbarSetThumb(wRedScrollbar, 0.0, 0.05);
232   wGreenScrollbar = XtCreateManagedWidget("wGreenScrollbar",
233 					  scrollbarWidgetClass,
234 					  wColorEditForm, NULL, 0);
235   XtAddCallback(wGreenScrollbar, XtNjumpProc,
236 		(XtCallbackProc)COLEDIT_ScrollbarMoved, NULL);
237   XawScrollbarSetThumb(wGreenScrollbar, 0.0, 0.05);
238   wBlueScrollbar = XtCreateManagedWidget("wBlueScrollbar",
239 					 scrollbarWidgetClass,
240 					 wColorEditForm, NULL, 0);
241   XtAddCallback(wBlueScrollbar, XtNjumpProc,
242 		(XtCallbackProc)COLEDIT_ScrollbarMoved, NULL);
243   XawScrollbarSetThumb(wBlueScrollbar, 0.0, 0.05);
244 
245   /* A sample country in the chosen color */
246   wSampleCountryForm = XtCreateManagedWidget("wSampleCountryForm",
247 					     labelWidgetClass,
248 					     wColorEditForm, NULL, 0);
249 
250   /* Input text label */
251   wColorInputLabel = XtCreateManagedWidget("wColorInputLabel",
252 					   labelWidgetClass,
253 					   wColorEditForm, NULL, 0);
254 
255   /* The actual widget for inputting text */
256   wColorInputText = XtVaCreateManagedWidget("wColorInputText",
257 					    asciiTextWidgetClass,
258 					    wColorEditForm,
259 					    XtNeditType, XawtextEdit, NULL);
260 
261   /* This is used to align the OK/Cancel buttons */
262   wColorDummy = XtCreateManagedWidget("wColorDummy", formWidgetClass,
263 				      wColorEditForm, NULL, 0);
264 
265   /* The buttons */
266   wColorOK = XtCreateManagedWidget("wColorOK",
267 				   commandWidgetClass,
268 				   wColorEditForm, NULL, 0);
269   XtAddCallback(wColorOK, XtNcallback, (XtCallbackProc)COLEDIT_Ok, NULL);
270   wColorCancel = XtCreateManagedWidget("wColorCancel",
271 				       commandWidgetClass,
272 				       wColorEditForm, NULL, 0);
273   XtAddCallback(wColorCancel, XtNcallback, (XtCallbackProc)COLEDIT_Cancel,
274 		NULL);
275 }
276 
277 
278 /** Cleanup macro for the function COLEDIT_EditColor */
279 #define COLEDIT_CloseColorDialog() \
280  UTIL_DisplayError(""); \
281  XtSetKeyboardFocus(wToplevel, wToplevel); \
282  XtRemoveGrab(wColorEditShell); \
283  XtUnrealizeWidget(wColorEditShell);
284 
285 
286 /**
287  * Displays the dialog with given color. Called by player add and
288  * registration routines.
289  *
290  * \b History:
291  * \arg 01.22.95  ESF  Created.
292  * \arg 01.26.95  ESF  Fixed last few bugs.
293  * \arg 23.08.95  JC   Use of COLOR_Depth.
294  * \arg 12.07.95  ESF  Made the editable color be the dice color.
295  */
COLEDIT_EditColor(Int32 iColorNum,Flag fStoreColor)296 String COLEDIT_EditColor(Int32 iColorNum, Flag fStoreColor)
297 {
298   XEvent   xEvent;
299   Int32    x, y;
300   CString  strNewColor=NULL;
301 
302   D_Assert(iColorNum >= COLOR_CountryToColor(0) && iColorNum <= COLOR_DieToColor(3),
303 	   "Asked to edit bogus color!");
304 
305   /* Center the new shell */
306   UTIL_CenterShell(wColorEditShell, wToplevel, &x, &y);
307   XtVaSetValues(wColorEditShell,
308 		XtNallowShellResize, False,
309 		XtNx, x,
310 		XtNy, y,
311 		XtNborderWidth, 1,
312 #ifdef ENGLISH
313 		XtNtitle, "Edit Color",
314 #endif
315 #ifdef FRENCH
316 		XtNtitle, "Edition des couleurs",
317 #endif
318 		NULL);
319 
320   /* Initialize the scrollbars to represent the right color */
321   COLEDIT_InitDialogWithColor(iColorNum);
322 
323   /* TdH looks wrong */
324   iCountry = COLOR_ColorToCountry(iColorNum);
325 
326   /* If the country requested was not a valid country, then
327    * pick a random country for the caller.
328    */
329 
330   if (iCountry >= NUM_COUNTRIES || iCountry < 0)
331     iCountry = rand() % NUM_COUNTRIES;
332 
333   /* Hide the dice */
334   DICE_Hide();
335 
336   /* Put the country on the sample */
337   pScaledSample = CARDS_GetCountryImage(iCountry,
338 				iColorNum,
339 				COLOR_CountryToColor(NUM_COUNTRIES));
340 
341   /* Scale it to the sample country form */
342   pScaledSample = CARDS_ScaleImage(pScaledSample, 100, 100);
343 
344   /* Set the initial color of the sample country
345    * TdH: to check!
346    */
347   COLOR_CopyColor(iColorNum, iColorNum);
348 
349   /* Dump it on the sample country location */
350   pixSampleImage = XCreatePixmap(hDisplay, pixMapImage, 140, 140, COLOR_GetDepth());
351   XSetForeground(hDisplay, hGC, COLOR_QueryColor(COLOR_CountryToColor(NUM_COUNTRIES)));
352   XFillRectangle(hDisplay, pixSampleImage, hGC, 0, 0, 140, 140);
353   XtVaSetValues(wSampleCountryForm, XtNbackground,
354 		COLOR_QueryColor(COLOR_CountryToColor(NUM_COUNTRIES)), NULL);
355   COLEDIT_UpdateExampleImage(iColorNum);
356 
357   /* Popup the color editing dialog */
358   XtMapWidget(wColorEditShell);
359   XtAddGrab(wColorEditShell, True, True);
360   XtSetKeyboardFocus(wToplevel, wColorEditShell);
361   XtSetKeyboardFocus(wColorEditShell, wColorInputText);
362 
363   /* Look until user presses one of the buttons */
364   iQueryResult = COLOR_EDIT_INPROGRESS;/* TdH: why this read?? */
365   while (iQueryResult == COLOR_EDIT_INPROGRESS)
366     {
367       /* pass events */
368       XNextEvent(hDisplay, &xEvent);
369       XtDispatchEvent(&xEvent);
370     }
371 
372   if (iQueryResult == COLOR_EDIT_OK)
373     {
374       Int32   i;
375 
376       /* Just in case the player typed a color name in and then hit "Ok"
377        * update the color in the country in the last second that the dialog
378        * is up, so that when we copy the color out of there it will be the
379        * color that the player typed in.
380        */
381 
382       COLEDIT_UpdateColorWithInput();
383 
384       /* Get the color from the text widget.  If the player moved the
385        * scrollbars, then the color will have been written in here.
386        * If the player typed something in, it will be in here.
387        */
388 
389       XtVaGetValues(wColorInputText, XtNstring, &strNewColor, NULL);
390 
391       /* Are we trying to store the color? */
392       if (fStoreColor) {
393 	  /* Sanity check */
394 	  if (iCountry < 0 || iCountry >= NUM_COUNTRIES ||
395 	      RISK_GetOwnerOfCountry(iCountry) == -1 ||
396 	      RISK_GetNumArmiesOfCountry(iCountry) <= 0)  {
397 	      (void)UTIL_PopupDialog("Error",
398 				     "Cannot set new value for color!",
399 				     1, "Ok", NULL, NULL);
400           } else {
401               Int32 iOwner = RISK_GetOwnerOfCountry(iCountry);
402               Flag isTrueColor = COLOR_IsTrueColor();
403 
404               /* And also the actual color for the player */
405               COLOR_StoreNamedColor(strNewColor, iOwner);
406 
407               /* Set all the countries that the player owns to be new color */
408               for (i=0; i!=NUM_COUNTRIES; i++)
409                   if (RISK_GetOwnerOfCountry(i) == iOwner) {
410                       COLOR_CopyColor(COLOR_DieToColor(0),
411                                       COLOR_CountryToColor(i));
412 
413                       if (isTrueColor) {
414                           COLOR_ColorCountry(i, iOwner);
415                           UTIL_DarkenCountry(i);
416                       }
417                   }
418 	      if (isTrueColor)
419                   STAT_RenderSlot(STAT_PlayerToSlot(iOwner), iOwner);
420 
421               /* If the player whose color changed is the current
422                * player, then recolor the current player indicator.
423                * Also, the dice really need to change color too
424                * (thanks, Kirsten, for reminding me about this -- who
425                * says English majors can't program?)  For now punt on
426                * the dice.
427                */
428 
429               if (RISK_GetOwnerOfCountry(iCountry) == iCurrentPlayer)
430                   COLOR_CopyColor(COLOR_DieToColor(0), COLOR_DieToColor(2));
431           }
432       }
433     }
434 
435   XDestroyImage(pScaledSample);
436 
437   COLEDIT_CloseColorDialog();
438   return strNewColor;
439 }
440 
441 
442 /**
443  * Updates color value and text box based on scrollbar movement.
444  * Called during X event handling from the scrollbar widget.
445  *
446  * \b History:
447  * \arg 01.22.95  ESF  Created.
448  */
COLEDIT_ScrollbarMoved(void)449 void COLEDIT_ScrollbarMoved(void)
450 {
451   float   r, g, b;
452   XColor  xColor;
453   char buf[256];
454 
455   XtVaGetValues(wRedScrollbar, XtNtopOfThumb, &r, NULL);
456   XtVaGetValues(wGreenScrollbar, XtNtopOfThumb, &g, NULL);
457   XtVaGetValues(wBlueScrollbar, XtNtopOfThumb, &b, NULL);
458 
459   /* Setup the new color */
460   xColor.red   = (Int32)((1.0-r)*65535.0);
461   xColor.green = (Int32)((1.0-g)*65535.0);
462   xColor.blue  = (Int32)((1.0-b)*65535.0);
463 
464   /* Color the sample country with the new color
465    */
466   COLOR_StoreColor(COLOR_DieToColor(0), xColor.red, xColor.green, xColor.blue);
467   COLEDIT_UpdateExampleImage(COLOR_DieToColor(0));
468   XFlush(hDisplay);
469 
470   /* Display the name of the color */
471   snprintf(buf, sizeof(buf), "#%02x%02x%02x",
472 	  xColor.red/256, xColor.green/256, xColor.blue/256);
473   XtVaSetValues(wColorInputText,
474 		XtNstring, buf,
475 		XtNinsertPosition, strlen(buf),
476 		NULL);
477 }
478 
479 
480 /**
481  * Parse value from input box, update scrollbars and example
482  * country image to reflect change. Uses XParseColor to
483  * handle named colors listed in rgb.txt
484  *
485  * \b History:
486  * \arg 01.23.95  ESF  Created.
487  */
COLEDIT_UpdateColorWithInput(void)488 void COLEDIT_UpdateColorWithInput(void)
489 {
490   CString  strColor;
491   float    r, g, b;
492   XColor   xColor1, xColor2;
493   char buf[256];
494 
495   /* Get the color from the text widget */
496   XtVaGetValues(wColorInputText, XtNstring, &strColor, NULL);
497 
498   /* Also get the color from the scrollbars. */
499   XtVaGetValues(wRedScrollbar, XtNtopOfThumb, &r, NULL);
500   XtVaGetValues(wGreenScrollbar, XtNtopOfThumb, &g, NULL);
501   XtVaGetValues(wBlueScrollbar, XtNtopOfThumb, &b, NULL);
502   snprintf(buf, sizeof(buf), "#%02x%02x%02x",
503 	  (Int32)((1.0-r)*65535.0)/256,
504 	  (Int32)((1.0-g)*65535.0)/256,
505 	  (Int32)((1.0-b)*65535.0)/256);
506 
507   /* Adjust for the screen */
508   xColor1.flags = DoRed | DoGreen | DoBlue;
509   (void)XParseColor(hDisplay, cmapColormap, buf, &xColor1);
510 
511 
512   /* Is it a valid color? */
513   if (XParseColor(hDisplay, cmapColormap, strColor, &xColor2))
514     {
515       /* If they match, then take this to mean the same as the "Ok" button. */
516         if (xColor1.red   == xColor2.red &&
517             xColor1.green == xColor2.green &&
518 	  xColor1.blue  == xColor2.blue)  {
519 	  COLEDIT_Ok();
520         }   else   {
521             COLOR_StoreColor(COLOR_DieToColor(0),
522                              xColor2.red, xColor2.green, xColor2.blue);
523             COLEDIT_InitDialogWithColor(COLOR_DieToColor(0));
524             COLEDIT_UpdateExampleImage(COLOR_DieToColor(0));
525         }
526     }  else
527 #ifdef ENGLISH
528     (void)UTIL_PopupDialog("Error", "That color does not exist!",
529 			   1, "Ok", NULL, NULL);
530 #endif
531 #ifdef FRENCH
532     (void)UTIL_PopupDialog("Erreur", "Cette couleur n'existe pas!",
533 			   1, "Ok", NULL, NULL);
534 #endif
535 }
536 
537 
538 /**
539  * Draw example country image with given color.
540  *
541  * \b History:
542  * \tag 09.01.00  MSH  Created.
543  */
COLEDIT_UpdateExampleImage(Int32 iColor)544 static void COLEDIT_UpdateExampleImage(Int32 iColor)
545 {
546   Int32    x, y;
547 
548   if (COLOR_IsTrueColor())
549     {
550       XSetForeground(hDisplay, hGC, COLOR_QueryColor(iColor));
551       for (y = 0; y < pScaledSample->height; y++)
552 	for (x = 0; x < pScaledSample->width; x++)
553 	  {
554 	    if (XGetPixel(pScaledSample, x, y) == NUM_COUNTRIES)
555 	      continue;
556 	    XDrawPoint(hDisplay, pixSampleImage, hGC,
557 		       (140-pScaledSample->width)/2 + x,
558 		       (140-pScaledSample->height)/2 + y);
559 	  }
560     }
561   else
562     {
563       XPutImage(hDisplay, pixSampleImage, hGC, pScaledSample, 0, 0,
564 	        (140-pScaledSample->width)/2, (140-pScaledSample->height)/2, 140, 140);
565     }
566 
567   XtVaSetValues(wSampleCountryForm, XtNbitmap, pixSampleImage, NULL);
568 }
569 
570 /* EOF */
571