1 /* Copyright (C) 1993, 1992 Nathan Sidwell */ 2 /* RCS $Id: makemred.c,v 4.30 1995/12/14 13:53:27 nathan Exp $ */ 3 /*{{{ includes*/ 4 #include "xmred.h" 5 #include "defmred.h" 6 #include <X11/Xaw/Form.h> 7 #include <X11/Xaw/Paned.h> 8 #include "makecom.c" 9 #include <X11/IntrinsicP.h> 10 #include <X11/CoreP.h> 11 #include "Icon.h" 12 #include "PixmapList.h" 13 #ifdef SCROLLBARBUGFIX 14 #include <X11/Xaw/Scrollbar.h> 15 #endif 16 /*}}}*/ 17 /*{{{ define*/ 18 /*{{{ gizmos*/ 19 #define GIZMO_MRED 0 20 #define GIZMO_PANE 1 21 #define GIZMO_MENU 2 22 #define GIZMO_ONE 3 23 #define GIZMO_ALL 4 24 #define GIZMO_GARDEN 5 25 #define GIZMO_PANEL 6 26 /*}}}*/ 27 /*}}}*/ 28 /*{{{ tables*/ 29 /*{{{ static GIZMO gizmos[] =*/ 30 static GIZMO gizmos[] = 31 { 32 {"mred", -1, &formWidgetClass}, 33 {"pane", GIZMO_MRED, &panedWidgetClass}, 34 {"menus", GIZMO_PANE, &panedWidgetClass}, 35 {"one", GIZMO_PANE, &panedWidgetClass}, 36 {"all", GIZMO_PANE, &panedWidgetClass}, 37 {"garden", GIZMO_ONE, &gardenWidgetClass}, 38 {"panel", GIZMO_ONE, &formWidgetClass}, 39 }; 40 /*}}}*/ 41 /*{{{ static Arg toplevel_args[] =*/ 42 static Arg toplevel_args[] = 43 { 44 {XtNinput, True}, 45 }; 46 /*}}}*/ 47 /*{{{ static Arg highlight_args[] =*/ 48 static Arg highlight_args[] = 49 { 50 {XtNforeground, (XtArgVal)0}, 51 }; 52 /*}}}*/ 53 /*{{{ static Arg color_args[] =*/ 54 static Arg color_args[] = 55 { 56 {XtNforeground, (XtArgVal)0}, 57 {XtNbackground, (XtArgVal)0}, 58 {XtNborderColor, (XtArgVal)0}, 59 {XtNinternalBorderColor, (XtArgVal)0}, 60 }; 61 /*}}}*/ 62 /*{{{ static char CONST *fallback_resources[] =*/ 63 static char CONST *fallback_resources[] = 64 { 65 #if __STDC__ 66 "Xmris.Font:" FONT_NAME, 67 #else 68 "Xmris.Font:", 69 #endif 70 "*TransientShell.allowShellResize:yes", 71 "*Text.useStringInPlace:no", 72 "*dialog*resize:yes", 73 "*load*Text*editType:textAppend", 74 "*comment*Text.baseTranslations:#override", 75 "*load*Text.baseTranslations:#override \ 76 <Key>Return:\n", 77 "*TransientShell.Dialog.Text.baseTranslations:#override \ 78 <Key>Return:set-dialog-button(agree)\n\ 79 Ctrl<Key>g:set-dialog-button(disagree)\n\ 80 <Key>Escape:set-dialog-button(disagree)\n", 81 "*dialog*ok.label:Ok", 82 "*dialog*continue.label:Continue", 83 "*dialog*retry.label:Retry", 84 "*dialog*cancel.label:Cancel", 85 "*dialog*clear.label:Clear", 86 "*dialog*abort.label:Abort", 87 "*dialog*default.label:Default", 88 "*altered.title:Altered", 89 "*showGrip:no", 90 "*mred.defaultDistance:0", 91 "*pane.orientation:vertical", 92 "*menus.orientation:horizontal", 93 "*menus*allowResize:yes", 94 "*menus*justify:left", 95 "*file.label:File", 96 "*garden.label:Garden", 97 "*menu.undo.label:Undo", 98 "*menu.redo.label:Redo", 99 "*menu.clear.label:Clear", 100 "*menu.new.label:New", 101 "*menu.load.label:Load", 102 "*menu.insert.label:Insert", 103 "*menu.save.label:Save", 104 "*menu.saveas.label:Save As", 105 "*menu.quit.label:Quit", 106 "*Form.borderWidth:0", 107 "*Label.borderWidth:0", 108 "*all.orientation:horizontal", 109 "*buffer.skipAdjust:yes", 110 "*buffer.Icon.top:chainTop", 111 "*buffer.Icon.bottom:chainTop", 112 "*all.gardens.orientation:vertical", 113 "*gardens.gardens.min:51", 114 "*gardens.orientation:horizontal", 115 "*gardens.scrollbar.orientation:horizontal", 116 "*gardens.scrollbar.height:12", 117 "*gardens.scrollbar.thumb:None", 118 "*gardens.scrollbar.skipAdjust:yes", 119 "*edit.skipAdjust:yes", 120 "*edit.Icon.top:chainTop", 121 "*edit.Icon.bottom:chainTop", 122 "*edit.include.fromHoriz:comment", 123 "*edit.garden.fromHoriz:include", 124 "*one.defaultDistance:0", 125 "*one.orientation:horizontal", 126 "*one.garden.skipAdjust:yes", 127 "*one.panel.attach:garden", 128 "*panel.defaultDistance:0", 129 "*panel*Label.internalHeight:0", 130 "*panel*Label.internalWidth:0", 131 "*controls.defaultDistance:0", 132 "*controls*left:chainLeft", 133 "*controls*right:chainLeft", 134 "*controls.Form.Icon.top:chainTop", 135 "*controls.Form.Icon.bottom:chainTop", 136 "*options.label.label:Options", 137 "*controls*Icon.fromVert:label", 138 "*options.random.fromHoriz:apple", 139 "*options.cherry.fromHoriz:random", 140 "*options.path.fromHoriz:cherry", 141 "*options.player.fromHoriz:path", 142 "*options.den.fromHoriz:player", 143 "*fills.fromVert:options", 144 "*fills.label.label:Fills", 145 "*fills.fill1.fromHoriz:fill0", 146 "*fills.fill2.fromHoriz:fill1", 147 "*fills.fill3.fromHoriz:fill2", 148 "*colors.fromVert:fills", 149 "*colors.label.label:Colors", 150 "*colors.color1.fromHoriz:color0", 151 "*colors.color2.fromHoriz:color1", 152 "*buttons.fromVert:colors", 153 "*buttons.label.label:Buttons", 154 "*buttons.button2.fromHoriz:button1", 155 "*buttons.button3.fromHoriz:button2", 156 "*buttons.button4.fromHoriz:button3", 157 "*buttons.button5.fromHoriz:button4", 158 "*buttons.button1.option:path", 159 "*buttons.button2.option:cherry", 160 "*buttons.button3.option:apple", 161 "*buttons.button4.option:random", 162 "*totals.fromVert:controls", 163 "*totals.left:chainLeft", 164 "*totals.right:chainLeft", 165 "*totals.label.label:Totals", 166 "*totals.label.horizDistance:4", 167 "*totals.Form.defaultDistance:0", 168 "*total0.fromVert:label", 169 "*total0.horizDistance:28", 170 "*total1.fromVert:total0", 171 "*total1.horizDistance:28", 172 "*total2.fromVert:total1", 173 "*total2.horizDistance:28", 174 "*total3.fromVert:total2", 175 "*total3.horizDistance:28", 176 "*total4.fromVert:label", 177 "*total4.horizDistance:30", 178 "*total5.fromVert:total4", 179 "*total5.horizDistance:30", 180 "*total6.fromVert:total5", 181 "*total6.horizDistance:30", 182 "*total7.fromVert:total6", 183 "*total7.horizDistance:30", 184 "*total4.fromHoriz:total0", 185 "*total5.fromHoriz:total1", 186 "*total6.fromHoriz:total2", 187 "*total7.fromHoriz:total3", 188 "*total8.fromVert:total3", 189 "*total8.horizDistance:28", 190 "*total9.fromHoriz:total8", 191 "*total9.fromVert:total7", 192 "*total9.horizDistance:30", 193 "*count.fromHoriz:icon", 194 "*count.horizDistance:4", 195 "*totals.total5.icon.fromHoriz:scrollbar", 196 "*totals.Form.icon.horizDistance:0", 197 "*total5.scrollbar.height:32", 198 "*total5.scrollbar.width:12", 199 "*total5.scrollbar.minimumThumb:1", 200 "*total5.scrollbar.thumb:None", 201 "*total5.scrollbar.baseTranslations:#override \ 202 ~Shift<KeyPress>space:StartScroll(Forward) NotifyScroll(FullLength) EndScroll()\n\ 203 Shift<KeyPress>space:StartScroll(Backward) NotifyScroll(FullLength) EndScroll()\n", 204 "*totals.Form.icon.fromHoriz:warning", 205 "*panel.totals.Form.warning.width:12", 206 "*panel.totals.Form.warning.internalHeight:5", 207 "*panel.totals.Form.warning.internalWidth:1", 208 "*panel.totals.Form.count.height:34", 209 "*panel.totals.Form.count.width:32", 210 "*totals.Form.count.resize:no", 211 "*totals.Form.left:chainLeft", 212 "*totals.Form.right:chainLeft", 213 "*totals.Form.top:chainTop", 214 "*totals.Form.bottom:chainTop", 215 "*panel.mode.fromVert:totals", 216 "*mode.fromHoriz:comment", 217 "*mode.horizDistance:40", 218 "*mode.Icon.left:chainRight", 219 "*mode.Icon.right:chainRight", 220 "*mode.label.left:chainRight", 221 "*mode.label.right:chainRight", 222 "*mode.Icon.top:chainTop", 223 "*mode.Icon.bottom:chainTop", 224 "*mode.label.top:chainTop", 225 "*mode.label.bottom:chainTop", 226 "*mode.label.label:Mode", 227 "*mode.label.height:32", 228 "*mode.combined.fromHoriz:label", 229 "*mode.separate.fromHoriz:combined", 230 "*mode.random.fromHoriz:separate", 231 "*mode.left:chainLeft", 232 "*mode.right:chainLeft", 233 "*mode.top:chainBottom", 234 "*mode.bottom:chainBottom", 235 "*panel.comment.fromVert:totals", 236 "*comment.vertDistance:4", 237 "*comment.horizDistance:4", 238 "*comment.left:chainLeft", 239 "*comment.right:chainLeft", 240 "*comment.top:chainBottom", 241 "*comment.bottom:chainBottom", 242 NULL 243 }; 244 /*}}}*/ 245 /*}}}*/ 246 /*{{{ prototypes*/ 247 /*}}}*/ 248 /*{{{ void create_gizmos(root, gizmos, num_gizmos)*/ 249 extern VOIDFUNC create_gizmos 250 FUNCARG((root, gizmos, num_gizmos), 251 Widget root 252 ARGSEP GIZMO *gizmos 253 ARGSEP Cardinal num_gizmos 254 ) 255 /* 256 * Creates a widget hierarchy according to the gizmo table 257 * supplied. 258 * The widget creation is done in this complicated fashion, so 259 * that the layout of form widget children can be specified in 260 * any order, and is not constrained by the order in which the 261 * widgets are created. 262 * I have also added an 'attach' resource for children of composite 263 * widgets. 264 */ 265 { 266 /*{{{ resources*/ 267 static char CONST *resources[] = 268 { 269 XtNfromHoriz, 270 XtNfromVert 271 }; 272 /*}}}*/ 273 GIZMO *gptr; 274 int parent; 275 int count; 276 Widget parent_widget; 277 int parent_form; 278 int parent_attach; 279 int ix; 280 281 count = num_gizmos; 282 while(count) 283 { 284 unsigned children; 285 286 for(gptr = gizmos, ix = num_gizmos; ix--; gptr++) 287 if(!gptr->widget && 288 (gptr->parent < 0 || gizmos[gptr->parent].widget)) 289 break; 290 assert(ix >= 0); 291 parent = gptr->parent; 292 parent_widget = parent < 0 ? root : gizmos[parent].widget; 293 parent_form = XtClass(parent_widget) == formWidgetClass; 294 parent_attach = XtIsComposite(parent_widget) && 295 !XtIsConstraint(parent_widget); 296 children = 0; 297 /*{{{ find siblings*/ 298 for(gptr = gizmos, ix = num_gizmos; ix--; gptr++) 299 if(gptr->parent == parent) 300 { 301 if(parent_form || parent_attach) 302 /*{{{ mark dependencies on siblings*/ 303 { 304 /*{{{ static XtResource formresources[] =*/ 305 static XtResource formresources[] = 306 { 307 {XtNfromHoriz, XtCWidget, XtRString, sizeof(String), 308 0 * sizeof(String), XtRImmediate, NULL}, 309 {XtNfromVert, XtCWidget, XtRString, sizeof(String), 310 1 * sizeof(String), XtRImmediate, NULL}, 311 }; 312 /*}}}*/ 313 /*{{{ static XtResource attachresources[] =*/ 314 static XtResource attachresources[] = 315 { 316 {"attach", XtCWidget, XtRString, sizeof(String), 317 0 * sizeof(String), XtRImmediate, NULL}, 318 }; 319 /*}}}*/ 320 unsigned ix; 321 unsigned child; 322 GIZMO *subptr; 323 String subrecs[2]; 324 325 subrecs[1] = NULL; 326 XtGetSubresources(parent_widget, (XtPointer)subrecs, 327 gptr->name, 328 ((CoreClassRec *)*gptr->class)->core_class.class_name, 329 parent_form ? formresources : attachresources, 330 parent_form ? XtNumber(formresources) : 331 XtNumber(attachresources), NULL, 0); 332 child = 0; 333 for(subptr = gizmos, ix = num_gizmos; ix--; subptr++) 334 if(subptr->parent == parent) 335 { 336 if(gptr != subptr) 337 { 338 unsigned i; 339 340 for(i = 2; i--;) 341 if(subrecs[i] && 342 !strcmp(subrecs[i], subptr->name)) 343 gptr->align[i] = num_gizmos - ix; 344 } 345 child++; 346 } 347 } 348 /*}}}*/ 349 children++; 350 } 351 /*}}}*/ 352 count -= children; 353 /* create the siblings */ 354 while(children--) 355 { 356 /*{{{ find a child*/ 357 { 358 GIZMO *fptr; 359 360 fptr = NULL; 361 for(gptr = gizmos, ix = num_gizmos; ix--; gptr++) 362 if(gptr->parent == parent && !gptr->widget) 363 { 364 if(!parent_attach || !gptr->align[0] || 365 gizmos[gptr->align[0] - 1].widget) 366 break; 367 if(!fptr) 368 fptr = gptr; 369 } 370 if(ix < 0) 371 gptr = fptr; 372 } 373 /*}}}*/ 374 /* create it */ 375 { 376 Arg args[2]; 377 unsigned nargs; 378 unsigned count; 379 WidgetClass class; 380 381 nargs = 0; 382 if(parent_form) 383 for(count = 2; count--;) 384 if(gptr->align[count]) 385 { 386 XtSetArg(args[nargs], (String)resources[count], NULL); 387 nargs++; 388 } 389 for(class = *gptr->class; class; 390 class = ((CoreClassPart *)class)->superclass) 391 if(class == shellWidgetClass) 392 { 393 gptr->widget = XtCreatePopupShell(gptr->name, 394 *gptr->class, parent_widget, args, nargs); 395 break; 396 } 397 if(!class) 398 gptr->widget = XtCreateManagedWidget(gptr->name, 399 *gptr->class, parent_widget, args, nargs); 400 if(gptr->args) 401 XtSetValues(gptr->widget, gptr->args, gptr->num_args); 402 #ifdef SCROLLBARBUGFIX 403 if(*gptr->class == scrollbarWidgetClass) 404 /* EMPTY */; 405 else 406 #endif 407 if(display.black || display.white) 408 XtSetValues(gptr->widget, color_args, XtNumber(color_args)); 409 if(data.mono == False && (*gptr->class == iconWidgetClass || 410 *gptr->class == pixmapListWidgetClass)) 411 XtSetValues(gptr->widget, highlight_args, 412 XtNumber(highlight_args)); 413 } 414 } 415 if(parent_form) 416 /*{{{ set args on siblings*/ 417 for(gptr = gizmos, ix = num_gizmos; ix--; gptr++) 418 if(gptr->parent == parent) 419 { 420 Arg args[2]; 421 unsigned nargs; 422 unsigned count; 423 424 nargs = 0; 425 for(count = 2; count--;) 426 if(gptr->align[count]) 427 { 428 XtSetArg(args[nargs], (String)resources[count], 429 gizmos[gptr->align[count] - 1].widget); 430 nargs++; 431 } 432 XtSetValues(gptr->widget, args, nargs); 433 } 434 /*}}}*/ 435 } 436 return; 437 } 438 /*}}}*/ 439 /*{{{ void create_widget()*/ 440 extern VOIDFUNC create_widget FUNCARGVOID 441 /* 442 * Create the graphics contexts, sprites and colours and stuff. 443 * sets visual and stuff for the toplevel widget 444 */ 445 { 446 gizmos[GIZMO_GARDEN].name = &names[data.gender != False][1]; 447 create_gizmos(display.toplevel, gizmos, XtNumber(gizmos)); 448 create_resources(gizmos[GIZMO_GARDEN].widget); 449 color_args[0].value = (XtArgVal)display.black; 450 color_args[1].value = (XtArgVal)display.white; 451 color_args[2].value = (XtArgVal)display.border; 452 color_args[3].value = (XtArgVal)display.border; 453 if(data.mono == False) 454 highlight_args[0].value = (XtArgVal)colors[COLOR_APPLE_FAINT].pixel; 455 install_menubar(gizmos[GIZMO_MENU].widget); 456 install_control(gizmos[GIZMO_PANEL].widget); 457 install_garden(gizmos[GIZMO_GARDEN].widget); 458 install_all(gizmos[GIZMO_ALL].widget); 459 install_dialogs(gizmos[GIZMO_MRED].widget); 460 return; 461 } 462 /*}}}*/ 463 /*{{{ void open_toolkit(arc, argv)*/ 464 extern VOIDFUNC open_toolkit 465 FUNCARG((argc, argv), 466 int argc 467 ARGSEP String *argv 468 ) 469 { 470 /*{{{ knr?*/ 471 #if !__STDC__ 472 { 473 char *ptr; 474 475 ptr = XtMalloc(strlen(fallback_resources[0]) + strlen(FONT_NAME) + 1); 476 strcpy(ptr, fallback_resources[0]); 477 strcat(ptr, FONT_NAME); 478 fallback_resources[0] = ptr; 479 } 480 #endif 481 /*}}}*/ 482 extract_options(&argc, argv, command_options); 483 default_gender = GAME_GENDER; 484 if(data.help == False) 485 { 486 XrmOptionDescRec CONST *ptr; 487 488 /* as options is an extern of unknown size, I can't use 489 * XtNumber() to get its size, so I've done it this way 490 */ 491 for(ptr = options; *(char CONST **)ptr; ptr++) 492 /* EMPTY */; 493 display.toplevel = XtAppInitialize(&display.context, "Xmris", 494 options, (Cardinal)(ptr - options), 495 (Cardinal *)&argc, (String *)argv, 496 (String *)fallback_resources, 497 toplevel_args, XtNumber(toplevel_args)); 498 if(argc > 1) 499 /*{{{ error*/ 500 { 501 unsigned ix; 502 503 data.help = True; 504 data.colors = False; 505 fprintf(stderr, "%s: Unknown option%s:", argv[0], 506 argc > 2 ? "s" : ""); 507 for(ix = 1; ix != argc; ix++) 508 fprintf(stderr, "%s %s", ix == 1 ? "" : ",", argv[ix]); 509 fputc('\n', stderr); 510 } 511 /*}}}*/ 512 else 513 { 514 XtResource CONST *ptr; 515 516 XtAppSetTypeConverter(display.context, XtRString, XtRGender, 517 convert_string2gender, (XtConvertArgRec *)NULL, 0, XtCacheNone, 518 (void (*)PROTOARG((XtAppContext, XrmValue *, XtPointer, 519 XrmValue *, Cardinal *)))NULL); 520 display.display = XtDisplay(display.toplevel); 521 for(ptr = resources; *(char CONST **)ptr; ptr++) 522 /* EMPTY */; 523 XtGetApplicationResources(display.toplevel, (XtPointer)&data, 524 resources, (Cardinal)(ptr - resources), (Arg *)NULL, 0); 525 #ifndef NDEBUG 526 XSetErrorHandler(error_handler); 527 #endif /* NDEBUG */ 528 gettoplevelresources(); 529 } 530 } 531 return; 532 } 533 /*}}}*/ 534