1 |
/* |
2 |
Copyright (C) 1993 Jarkko Sonninen & Petri Heinila |
3 |
|
4 |
This program is free software; you can redistribute it and/or modify |
5 |
it under the terms of the GNU General Public License as published by |
6 |
the Free Software Foundation; either version 2 of the License, or |
7 |
(at your option) any later version. |
8 |
|
9 |
This program is distributed in the hope that it will be useful, |
10 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 |
GNU General Public License for more details. |
13 |
|
14 |
You should have received a copy of the GNU General Public License |
15 |
along with this program; if not, write to the Free Software |
16 |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
17 |
|
18 |
The authors can be reached via e-mail to Jarkko.Sonninen@lut.fi |
19 |
or Petri.Heinila@lut.fi . |
20 |
*/ |
21 |
|
22 |
|
23 |
|
24 |
#include "Posix.h" |
25 |
#include "Attr.h" |
26 |
#include "X11.h" |
27 |
#include "CrList.h" |
28 |
#include "CrFace.h" |
29 |
#include "CrEdit.h" |
30 |
#include "Cnv.h" |
31 |
#include "Edit.h" |
32 |
#include "App.h" |
33 |
#include "loader.h" |
34 |
#include "debug.h" |
35 |
|
36 |
static void AttrReset(Attr self); |
37 |
|
38 |
/* variables, combination bit */ |
39 |
#define T_Path (1<<I_Path) |
40 |
#define T_X (1<<I_X) |
41 |
#define T_Y (1<<I_Y) |
42 |
#define T_Weight (1<<I_Weight) |
43 |
#define T_Connect (1<<I_Connect) |
44 |
#define T_Hp (1<<I_Hp) |
45 |
#define T_Trigger (1<<I_Trigger) |
46 |
#define T_Sacrifice (1<<I_Sacrifice) |
47 |
#define T_Count (1<<I_Count) |
48 |
#define T_Lockcode (1<<I_Lockcode) /* slaying - field */ |
49 |
#define T_Direction (1<<I_Direction) |
50 |
#define T_Rotation (1<<I_Rotation) |
51 |
#define T_NoPick (1<<I_NoPick) |
52 |
#define T_Unique (1<<I_Unique) |
53 |
#define T_WeightL (1<<I_WeightL) |
54 |
#define T_Brand (1<<I_Brand) |
55 |
#define T_Maker (1<<I_Maker) |
56 |
|
57 |
/*** types ar Combinations ***/ |
58 |
#define T_Exit (T_Path | T_X | T_Y ) |
59 |
#define T_Trapdoor (T_Weight | T_X | T_Y ) |
60 |
#define T_Connected (T_Connect ) |
61 |
#define T_Pit (T_Connect | T_X | T_Y ) |
62 |
#define T_Monster (T_Hp ) |
63 |
#define T_Pedestal (T_Connected | T_Trigger ) |
64 |
#define T_Altar (T_Connected | T_Sacrifice | T_Count ) |
65 |
#define T_Button (T_Weight | T_Connected) |
66 |
#define T_Director (T_Connected | T_Direction | T_Rotation) |
67 |
#define T_Lockdoor (T_Lockcode) |
68 |
#define T_Key (T_Lockcode | T_Unique) |
69 |
#define T_Container (T_Lockcode | T_WeightL | T_Brand | T_Unique | T_NoPick) |
70 |
#define T_Sign 0 |
71 |
#define T_Map (T_X | T_Y | T_Path) |
72 |
|
73 |
#define T_Default 0 |
74 |
|
75 |
/* |
76 |
* transfer type from game to editor, return negative on error |
77 |
* |
78 |
* Basically, for certain things, we want to have default values set up. |
79 |
*/ |
80 |
int GetType (object *tmp) |
81 |
{ |
82 |
if (!tmp) |
83 |
return (-1); |
84 |
|
85 |
if (tmp->head) |
86 |
tmp = tmp->head; |
87 |
|
88 |
switch (tmp->type) { |
89 |
case TELEPORTER: |
90 |
return T_Connected|T_Exit; |
91 |
case PLAYER_CHANGER: |
92 |
case EXIT: |
93 |
return T_Exit; |
94 |
case TRAPDOOR: |
95 |
return T_Trapdoor; |
96 |
case HOLE: |
97 |
return T_Pit; |
98 |
case BUTTON: |
99 |
case TRIGGER_BUTTON: |
100 |
return T_Button; |
101 |
case CREATOR: |
102 |
return T_Connected|T_Maker; |
103 |
case CONVERTER: |
104 |
return T_Maker|T_Lockcode; |
105 |
case GATE: |
106 |
case CF_HANDLE: |
107 |
case TIMED_GATE: |
108 |
case MAGIC_EAR: |
109 |
case TRIGGER: |
110 |
return T_Connected; |
111 |
case CHECK_INV: |
112 |
return T_Connected | T_Lockcode; |
113 |
case ALTAR: |
114 |
case TRIGGER_ALTAR: |
115 |
return T_Altar; |
116 |
case PEDESTAL: |
117 |
case TRIGGER_PEDESTAL: |
118 |
return T_Pedestal; |
119 |
case BOOK: |
120 |
case SIGN: |
121 |
return T_Sign; |
122 |
case MARKER: |
123 |
case LOCKED_DOOR: |
124 |
return T_Lockdoor; |
125 |
case SPECIAL_KEY: |
126 |
return T_Key; |
127 |
case MAP: /* shouldn't happen ... */ |
128 |
return T_Map; |
129 |
case DIRECTOR: |
130 |
case FIREWALL: |
131 |
return (NUM_ANIMATIONS(tmp) > 0) |
132 |
? T_Director : T_Connected; |
133 |
case CONTAINER: |
134 |
return T_Container; |
135 |
default: |
136 |
if (QUERY_FLAG(tmp, FLAG_MONSTER)) |
137 |
return T_Monster; |
138 |
else |
139 |
return T_Default; |
140 |
} |
141 |
/* return -1; */ |
142 |
} |
143 |
|
144 |
/********************************************************************** |
145 |
*Section: get value from object for displying |
146 |
*Commentary: |
147 |
* Remeber, the strings from obejct may be NULL's |
148 |
**********************************************************************/ |
149 |
|
150 |
static void getX (object *ob, char *str, XtPointer c) { |
151 |
sprintf(str,"%d",EXIT_X(ob)); |
152 |
} |
153 |
|
154 |
static void getY (object *ob, char *str, XtPointer c) { |
155 |
sprintf(str,"%d",EXIT_Y(ob)); |
156 |
} |
157 |
|
158 |
static void getPath (object *ob, char *str, XtPointer c) { |
159 |
strcpy (str, EXIT_PATH(ob) ? EXIT_PATH(ob) : ""); |
160 |
} |
161 |
|
162 |
static void getWeight (object *ob, char *str, XtPointer c) { |
163 |
sprintf(str,"%d",ob->weight); |
164 |
} |
165 |
|
166 |
/*** connected ***/ |
167 |
static void getConnect (object *ob, char *str, XtPointer c) { |
168 |
sprintf(str,"%d",get_button_value(ob)); |
169 |
} |
170 |
|
171 |
static void getHp (object *ob, char *str, XtPointer c) { |
172 |
sprintf(str,"%d",ob->stats.hp); |
173 |
} |
174 |
|
175 |
#define NotUsed "(not-used)" |
176 |
|
177 |
static void getTrigger (object *ob, char *str, XtPointer c) { |
178 |
if(!ob->slaying || !*ob->slaying) |
179 |
sprintf(str,NotUsed); |
180 |
else |
181 |
strcpy (str, ob->slaying); |
182 |
} |
183 |
|
184 |
/*** sacrifice ***/ |
185 |
static void getSacrifice (object *ob, char *str, XtPointer c) { |
186 |
if(!ob->slaying || !*ob->slaying) { |
187 |
if(!ob->arch->clone.slaying) |
188 |
LOG(llevError,"missing sacrifice for altar\n"); |
189 |
strcpy (str, ob->arch->clone.slaying); |
190 |
} else |
191 |
strcpy (str, ob->slaying); |
192 |
} |
193 |
|
194 |
static void getCount (object *ob, char *str, XtPointer c) { |
195 |
sprintf(str,"%d",ob->stats.food); |
196 |
} |
197 |
|
198 |
/*** lockcode ***/ |
199 |
static void getLockcode (object *ob, char *str, XtPointer c) { |
200 |
if(!ob->slaying || !*ob->slaying) { |
201 |
sprintf(str,NotUsed); |
202 |
} else |
203 |
strcpy (str, ob->slaying); |
204 |
} |
205 |
|
206 |
/*** direction ***/ |
207 |
static void getDirection (object *ob, char *str, XtPointer c) { |
208 |
sprintf(str,"%d",ob->stats.maxsp); |
209 |
} |
210 |
|
211 |
/*** rotation ***/ |
212 |
static void getRotation (object *ob, char *str, XtPointer c) { |
213 |
sprintf(str,"%d",ob->stats.sp); |
214 |
} |
215 |
|
216 |
/*** unique ***/ |
217 |
static void getUnique (object *ob, char *str, XtPointer c) { |
218 |
*str = QUERY_FLAG(ob, FLAG_UNIQUE) ? ~0 : 0; |
219 |
} |
220 |
|
221 |
/*** no pick ***/ |
222 |
static void getNoPick (object *ob, char *str, XtPointer c) { |
223 |
*str = QUERY_FLAG(ob, FLAG_NO_PICK) ? ~0 : 0; |
224 |
} |
225 |
|
226 |
/*** weight limit ***/ |
227 |
static void getWeightL (object *ob, char *str, XtPointer c) { |
228 |
sprintf(str,"%d",ob->weight_limit); |
229 |
} |
230 |
|
231 |
/*** brand ***/ |
232 |
static void getBrand (object *ob, char *str, XtPointer c) { |
233 |
if(!ob->race || !*ob->race) |
234 |
sprintf(str,NotUsed); |
235 |
else |
236 |
sprintf(str,"%s",ob->race); |
237 |
} |
238 |
|
239 |
/*** brand ***/ |
240 |
static void getMakes (object *ob, char *str, XtPointer c) { |
241 |
if(!ob->other_arch) |
242 |
sprintf(str,NotUsed); |
243 |
else |
244 |
sprintf(str,"%s",ob->other_arch->name); |
245 |
} |
246 |
|
247 |
/* |
248 |
* putValue functions |
249 |
* |
250 |
*/ |
251 |
|
252 |
/*** coord ***/ |
253 |
static void putX (object *ob, char *str, XtPointer c) { |
254 |
EXIT_X(ob) = atoi(str); |
255 |
} |
256 |
|
257 |
static void putY (object *ob, char *str, XtPointer c) { |
258 |
EXIT_Y(ob) = atoi(str); |
259 |
} |
260 |
|
261 |
/*** path ***/ |
262 |
static void putPath (object *ob, char *str, XtPointer c) { |
263 |
if(EXIT_PATH(ob)) free_string(EXIT_PATH(ob)); |
264 |
EXIT_PATH(ob) = NULL; |
265 |
if(strlen(str)) EXIT_PATH(ob) = add_string(str); |
266 |
} |
267 |
|
268 |
/*** sacrifice ***/ |
269 |
static void putSacrifice (object *ob, char *str, XtPointer c) { |
270 |
if(ob->slaying) free_string(ob->slaying); |
271 |
ob->slaying = add_string(str); |
272 |
} |
273 |
|
274 |
/*** trigger ***/ |
275 |
static void putTrigger (object *ob, char *str, XtPointer c) { |
276 |
if(!strcmp(str,NotUsed)) |
277 |
ob->slaying = NULL; |
278 |
else { |
279 |
if(ob->slaying) free_string(ob->slaying); |
280 |
ob->slaying = add_string(str); |
281 |
} |
282 |
} |
283 |
|
284 |
/*** weight ***/ |
285 |
static void putWeight (object *ob, char *str, XtPointer c) { |
286 |
ob->weight = atoi(str); |
287 |
} |
288 |
|
289 |
/*** connect ***/ |
290 |
static void putConnect (object *ob, char *str, XtPointer c) { |
291 |
if (QUERY_FLAG(ob, FLAG_IS_LINKED)) |
292 |
remove_button_link(ob); |
293 |
add_button_link(ob, ob->map, atoi(str)); |
294 |
} |
295 |
|
296 |
/*** hp ***/ |
297 |
static void putHp (object *ob, char *str, XtPointer c) { |
298 |
ob->stats.hp = atoi(str); |
299 |
} |
300 |
|
301 |
/*** count ***/ |
302 |
static void putCount (object *ob, char *str, XtPointer c) { |
303 |
ob->stats.food = atoi(str); |
304 |
} |
305 |
|
306 |
/*** lockcode ***/ |
307 |
static void putLockcode (object *ob, char *str, XtPointer c) { |
308 |
if(!strcmp(str,NotUsed)) |
309 |
ob->slaying = NULL; |
310 |
else { |
311 |
if(ob->slaying) free_string(ob->slaying); |
312 |
ob->slaying = add_string(str); |
313 |
} |
314 |
} |
315 |
|
316 |
/*** direction ***/ |
317 |
static void putDirection (object *ob, char *str, XtPointer c) { |
318 |
ob->stats.maxsp = atoi(str); |
319 |
animate_object (ob, ob->direction); |
320 |
} |
321 |
|
322 |
/*** rotation ***/ |
323 |
static void putRotation (object *ob, char *str, XtPointer c) { |
324 |
ob->stats.sp = atoi(str); |
325 |
animate_object (ob, ob->direction); |
326 |
} |
327 |
|
328 |
/*** unique ***/ |
329 |
static void putUnique (object *ob, char *str, XtPointer c) { |
330 |
*str ? SET_FLAG(ob, FLAG_UNIQUE) : CLEAR_FLAG(ob, FLAG_UNIQUE); |
331 |
} |
332 |
|
333 |
/*** no pick ***/ |
334 |
static void putNoPick (object *ob, char *str, XtPointer c) { |
335 |
*str ? SET_FLAG(ob, FLAG_NO_PICK) : CLEAR_FLAG(ob, FLAG_NO_PICK); |
336 |
} |
337 |
|
338 |
/*** weight limit ***/ |
339 |
static void putWeightL (object *ob, char *str, XtPointer c) { |
340 |
debug0("NO putWeightL\n"); |
341 |
} |
342 |
|
343 |
/*** brand ***/ |
344 |
static void putBrand (object *ob, char *str, XtPointer c) { |
345 |
if(!strcmp(str,NotUsed)) |
346 |
ob->race = NULL; |
347 |
else { |
348 |
if(ob->race) free_string(ob->race); |
349 |
ob->race = add_string(str); |
350 |
} |
351 |
} |
352 |
|
353 |
static void putMakes (object *ob, char *str, XtPointer c) { |
354 |
if(!strcmp(str,NotUsed)) |
355 |
ob->other_arch = NULL; |
356 |
else { |
357 |
ob->other_arch = find_archetype(str); |
358 |
} |
359 |
} |
360 |
|
361 |
|
362 |
/********************************************************************** |
363 |
* tags |
364 |
**********************************************************************/ |
365 |
|
366 |
AttrDef AttrDescription[] = { |
367 |
{"Path", TypeString, getPath, putPath}, |
368 |
{"X", TypeString, getX, putX}, |
369 |
{"Y", TypeString, getY, putY}, |
370 |
{"Weight", TypeString, getWeight, putWeight}, |
371 |
{"Connect", TypeString, getConnect, putConnect}, |
372 |
{"Hp", TypeString, getHp, putHp}, |
373 |
{"Trigger", TypeString, getTrigger, putTrigger}, |
374 |
{"Sacrifice", TypeString, getSacrifice, putSacrifice}, |
375 |
{"Count", TypeString, getCount, putCount}, |
376 |
{"Lockcode", TypeString, getLockcode, putLockcode}, |
377 |
{"Direction", TypeString, getDirection, putDirection}, |
378 |
{"Rotation", TypeString, getRotation, putRotation}, |
379 |
{"No Pick", TypeToggle, getNoPick, putNoPick}, |
380 |
{"Unique", TypeToggle, getUnique, putUnique}, |
381 |
{"WeightL", TypeString, getWeightL, putWeightL}, |
382 |
{"Brand", TypeString, getBrand, putBrand}, |
383 |
{"Makes", TypeString, getMakes, putMakes}, /* other_arch */ |
384 |
{NULL, 0, 0, NULL} |
385 |
}; |
386 |
|
387 |
char *allowed_variables[] = { |
388 |
|
389 |
"name", "race", "slaying", "other_arch", "last_heal", "last_sp", |
390 |
"last_eat", "speed", "speed_left", "slow_move", "face", "Str", "Dex", |
391 |
"Con", "Wis", "Cha", "Int", "Pow", "hp", "maxhp", "sp", "maxsp", "exp", |
392 |
"food", "dam", "wc", "ac", "nrof", "level", "direction", "type", |
393 |
"material", "value", "weight", "carrying", "immune", "protected", |
394 |
"attacktype", "vulnerable", "path_attuned", "path_repelled", |
395 |
"path_denied", "invisible", "magic", "state", "alive", "applied", |
396 |
"unpaid", "need_an", "need_ie", "no_pick", "no_pass", "walk_on", |
397 |
"walk_off", "fly_on", "fly_off", "flying", "monster", |
398 |
"neutral", "no_attack", "no_damage", "friendly", |
399 |
"generator", "is_thrown", "auto_apply", "treasure", "apply_once", |
400 |
"see_invisible", "can_roll", "is_turning", "is_turnable", "is_used_up", |
401 |
"identified", "reflecting", "changing", "splitting", "hitback", |
402 |
"startequip", "blocksview", "undead", "scared", "unaggressive", |
403 |
"reflect_missile", "reflect_spell", "no_magic", "wiz", "was_wiz", |
404 |
"tear_down", "luck", "run_away", "pass_thru", "can_pass_thru", |
405 |
"pick_up", "anim_speed", "container", "no_drop", "no_pretext", |
406 |
"will_apply", "random_movement", "can_apply", "can_cast_spell", |
407 |
"can_use_scroll", "can_use_wand", "can_use_bow", "can_use_armour", |
408 |
"can_use_weapon", "can_use_ring", "has_ready_wand", "has_ready_bow", |
409 |
"xrays", "is_floor", "lifesave", "no_strength", "sleep", "stand_still", |
410 |
"random_move", "only_attack", "armour", "attack_movement", "move_state", |
411 |
"confused", "stealth", "connected", "cursed", "damned", "see_anywhere", |
412 |
"known_magical", "known_cursed", "can_use_skill", "been_applied", |
413 |
"title", "has_ready_rod", "can_use_rod", "has_ready_horn", |
414 |
"can_use_horn", "expmul", "unique", "make_invisible", "is_wooded", |
415 |
"is_hilly", "has_ready_skill", "has_ready_weapon", "no_skill_ident", |
416 |
"glow_radius", "is_blind", "can_see_in_dark", "is_cauldron", |
417 |
"randomitems", "is_dust", "no_steal", "one_hit","berserk", |
418 |
"sub_type", "sub_type2","casting_speed", "elevation", |
419 |
"save_on_overlay", |
420 |
/* GROS - These are hooks for script events */ |
421 |
"script_load","script_apply","script_say","script_trigger", "script_time", |
422 |
"script_attack","script_drop", "script_throw", "script_stop", "script_death", "current_weapon_script", |
423 |
"start_script_load", "start_script_apply","start_script_say","start_script_trigger","start_script_time", |
424 |
"start_script_attack","start_script_drop","start_script_throw","start_script_stop", "start_script_death", |
425 |
"end_script_load", "end_script_apply","end_script_say","end_script_trigger","end_script_time", |
426 |
"end_script_attack","end_script_drop","end_script_throw","end_script_stop", "end_script_death", |
427 |
|
428 |
#ifdef NPC_PROG |
429 |
"npc_status", "npc_program", |
430 |
#endif |
431 |
|
432 |
/* Resistances */ "resist_physical", "resist_magic", "resist_fire", |
433 |
"resist_electricity", "resist_cold", "resist_confusion", "resist_acid", |
434 |
"resist_drain", "resist_weaponmagic", "resist_ghosthit", "resist_poison", |
435 |
"resist_slow", "resist_paralyze", "resist_turn_undead", "resist_fear", |
436 |
"resist_cancellation", "resist_deplete", "resist_death", "resist_chaos", |
437 |
"resist_counterspell", "resist_godpower", "resist_holyword", |
438 |
"resist_blind", "elevation" |
439 |
|
440 |
}; |
441 |
|
442 |
#define ALLOWED_VARIABLES (sizeof(allowed_variables) / sizeof (char *)) |
443 |
|
444 |
/********************************************************************** |
445 |
* widgets |
446 |
**********************************************************************/ |
447 |
|
448 |
/* |
449 |
* member: create tag widgets |
450 |
* parent: parent container |
451 |
*/ |
452 |
static void AttrTagsCreate(Attr self,Widget parent) |
453 |
{ |
454 |
int i; |
455 |
self->attrnumber = 0; |
456 |
while (self->desc[self->attrnumber].label) |
457 |
self->attrnumber++; |
458 |
|
459 |
self->tags = (AttrTags*)XtCalloc(self->attrnumber,sizeof(AttrTags)); |
460 |
for(i=0; i < self->attrnumber; i++) { |
461 |
if (self->desc[i].type == TypeString) { |
462 |
self->tags[i].cont = XtVaCreateWidget |
463 |
("box",boxWidgetClass,parent, |
464 |
XtNorientation,XtorientHorizontal, |
465 |
NULL); |
466 |
XtVaCreateManagedWidget |
467 |
("label",labelWidgetClass,self->tags[i].cont, |
468 |
XtNlabel,self->desc[i].label, |
469 |
NULL); |
470 |
self->tags[i].value = XtVaCreateManagedWidget |
471 |
("value",asciiTextWidgetClass,self->tags[i].cont, |
472 |
XtNtype,XawAsciiString, |
473 |
XtNeditType,XawtextEdit, |
474 |
NULL); |
475 |
} |
476 |
} |
477 |
for(i=0; i < self->attrnumber; i++) { |
478 |
if (self->desc[i].type == TypeToggle) { |
479 |
self->tags[i].cont = XtVaCreateWidget |
480 |
("box",boxWidgetClass,parent, |
481 |
XtNorientation,XtorientHorizontal, |
482 |
NULL); |
483 |
|
484 |
self->tags[i].value = XtVaCreateManagedWidget |
485 |
("toggle",toggleWidgetClass, self->tags[i].cont, |
486 |
XtNlabel,self->desc[i].label, |
487 |
NULL); |
488 |
} |
489 |
} |
490 |
} |
491 |
|
492 |
|
493 |
/* |
494 |
* callback: receive ok |
495 |
*/ |
496 |
static void AttrOkCb(Widget w,XtPointer client,XtPointer call) |
497 |
{ |
498 |
Attr self = (Attr)client; |
499 |
|
500 |
AttrApply(self); |
501 |
AttrDestroy (self); |
502 |
} |
503 |
|
504 |
/* |
505 |
* receive apply |
506 |
*/ |
507 |
static void AttrApplyCb(Widget w,XtPointer client,XtPointer call) |
508 |
{ |
509 |
Attr self = (Attr)client; |
510 |
AttrApply(self); |
511 |
} |
512 |
|
513 |
/* |
514 |
* receive cancel |
515 |
*/ |
516 |
static void AttrCancelCb(Widget w,XtPointer client,XtPointer call) |
517 |
{ |
518 |
Attr self = (Attr)client; |
519 |
|
520 |
AttrDestroy(self); |
521 |
} |
522 |
|
523 |
/* |
524 |
* receive dump |
525 |
*/ |
526 |
static void AttrDumpCb(Widget w,XtPointer client,XtPointer call) |
527 |
{ |
528 |
Attr self = (Attr)client; |
529 |
|
530 |
dump_object(self->op); |
531 |
CnvBrowseShowString(self->dump,errmsg); |
532 |
} |
533 |
|
534 |
/********************************************************************** |
535 |
* widget-message |
536 |
**********************************************************************/ |
537 |
|
538 |
|
539 |
static CrListNode AttrInventoryNext(XtPointer client,XtPointer call) |
540 |
{ |
541 |
Attr self = (Attr)client; |
542 |
CrListNode retNode = (CrListNode)call; |
543 |
static struct _CrListNode node; |
544 |
object *op = NULL; |
545 |
|
546 |
if (!self->op) |
547 |
return (CrListNode)NULL; |
548 |
|
549 |
if(retNode) { /* next */ |
550 |
op = ((object *)retNode->ptr)->below; |
551 |
} else { /* begin */ |
552 |
op = self->op->inv; |
553 |
} |
554 |
|
555 |
if(op) { |
556 |
node.face = op->face; |
557 |
node.name = op->name; |
558 |
node.ptr = (XtPointer)op; |
559 |
return &node; |
560 |
} |
561 |
return (CrListNode)NULL; |
562 |
} |
563 |
|
564 |
/* |
565 |
* callback: insert object |
566 |
*/ |
567 |
static void InsertCb(Widget w,XtPointer client,XtPointer call) |
568 |
{ |
569 |
Attr self = (Attr)client; |
570 |
/* CrListCall ret = (CrListCall)call; */ |
571 |
object *obj; |
572 |
|
573 |
if((obj = AppItemGetObject(self->app)) && AttrGetObject(self)) { |
574 |
debug1("Attr-InsertCb() %s\n",obj->name); |
575 |
(void) insert_ob_in_ob(object_create_clone(obj),AttrGetObject(self)); |
576 |
} |
577 |
} |
578 |
|
579 |
/* |
580 |
* create recursively attributes from inventory |
581 |
*/ |
582 |
static void AttrInventorySelectCb(Widget w,XtPointer client,XtPointer call) |
583 |
{ |
584 |
Attr self = (Attr)client; |
585 |
CrListCall p = (CrListCall)call; |
586 |
object *ob = (object *)p->node; |
587 |
|
588 |
if (self->attr) { |
589 |
AttrDestroy (self->attr); |
590 |
} |
591 |
|
592 |
self->attr = AttrCreate("attr",self->app, ob, |
593 |
AttrDescription, GetType(ob), self->client); |
594 |
} |
595 |
|
596 |
/* |
597 |
* callback: delete object from look window |
598 |
*/ |
599 |
static void DeleteCb(Widget w,XtPointer client,XtPointer call) |
600 |
{ |
601 |
Attr self = (Attr)client; |
602 |
CrListCall ret = (CrListCall)call; |
603 |
object *obj = ret->node; |
604 |
|
605 |
debug1("Attr-DeleteCb() %s\n",obj->name); |
606 |
if (self->attr && self->attr->op == obj) |
607 |
AttrDestroy (self->attr); |
608 |
remove_ob(obj); |
609 |
free_object(obj); |
610 |
} |
611 |
|
612 |
/********************************************************************** |
613 |
* widget - variables |
614 |
**********************************************************************/ |
615 |
|
616 |
/* |
617 |
* |
618 |
*/ |
619 |
static void AttrVarSelectCb(Widget w,XtPointer client,XtPointer call) |
620 |
{ |
621 |
Attr self = (Attr)client; |
622 |
XawListReturnStruct *ret = (XawListReturnStruct*)call; |
623 |
XtVaSetValues(self->iw.var, |
624 |
XtNstring,ret->string, |
625 |
NULL); |
626 |
XtPopdown(self->vars.shell); |
627 |
} |
628 |
|
629 |
/* |
630 |
* |
631 |
*/ |
632 |
static void AttrVarCancelCb(Widget w,XtPointer client,XtPointer call) |
633 |
{ |
634 |
Attr self = (Attr)client; |
635 |
XtPopdown(self->vars.shell); |
636 |
} |
637 |
|
638 |
/* |
639 |
* compare funtion for sorting in PathListGet() |
640 |
*/ |
641 |
static int StrCmp (const void **s1, const void **s2) |
642 |
{ |
643 |
return strcmp (*s1, *s2); |
644 |
} |
645 |
|
646 |
/* |
647 |
* create widget layout for selectin variable from list |
648 |
*/ |
649 |
static void AttrVarLayout(Attr self,Widget parent) |
650 |
{ |
651 |
Widget form,cancel,view; |
652 |
|
653 |
self->vars.shell = XtVaCreatePopupShell |
654 |
("vars",transientShellWidgetClass,parent, |
655 |
NULL); |
656 |
form = XtVaCreateManagedWidget |
657 |
("form",formWidgetClass,self->vars.shell, |
658 |
NULL); |
659 |
view = XtVaCreateManagedWidget |
660 |
("view",viewportWidgetClass,form, |
661 |
NULL); |
662 |
self->vars.list = XtVaCreateManagedWidget |
663 |
("list",listWidgetClass,view, |
664 |
NULL); |
665 |
XtAddCallback(self->vars.list,XtNcallback,AttrVarSelectCb,(XtPointer)self); |
666 |
/*** sort varibales ***/ |
667 |
|
668 |
qsort(allowed_variables, ALLOWED_VARIABLES, |
669 |
sizeof(char *),(int (*)())StrCmp); |
670 |
|
671 |
XawListChange(self->vars.list,allowed_variables, |
672 |
ALLOWED_VARIABLES, 0, True); |
673 |
cancel = XtVaCreateManagedWidget |
674 |
("cancel",commandWidgetClass,form, |
675 |
XtNfromVert,view, |
676 |
NULL); |
677 |
XtAddCallback(cancel,XtNcallback,AttrVarCancelCb,(XtPointer)self); |
678 |
CnvCenterWidget(self->vars.shell); |
679 |
} |
680 |
|
681 |
/* |
682 |
* |
683 |
*/ |
684 |
static void AttrVarGetCb(Widget w,XtPointer client,XtPointer call) |
685 |
{ |
686 |
Attr self = (Attr)client; |
687 |
XtPopup(self->vars.shell,XtGrabExclusive); |
688 |
} |
689 |
|
690 |
/********************************************************************** |
691 |
* members |
692 |
**********************************************************************/ |
693 |
|
694 |
void AppLayout(Attr self,Widget parent, char *name) |
695 |
{ |
696 |
Widget form,view1,pane; |
697 |
Widget ok,apply,cancel; |
698 |
Widget view; |
699 |
|
700 |
self->shell = XtVaCreatePopupShell |
701 |
(name, topLevelShellWidgetClass, parent, NULL); |
702 |
form = XtVaCreateManagedWidget("form",formWidgetClass,self->shell,NULL); |
703 |
|
704 |
self->iw.name = XtVaCreateManagedWidget |
705 |
("name",asciiTextWidgetClass,form, |
706 |
XtNtype,XawAsciiString, |
707 |
XtNeditType,XawtextEdit, |
708 |
XtNresize,False, |
709 |
XtNadjust,False, |
710 |
NULL); |
711 |
|
712 |
self->iw.face = XtVaCreateManagedWidget |
713 |
("face",crFaceWidgetClass,form, |
714 |
XtNfromVert,self->iw.name, |
715 |
XtNresize,True, |
716 |
XtNadjust,False, |
717 |
XtNobject,self->op, |
718 |
NULL); |
719 |
|
720 |
/*** dump ***/ |
721 |
self->iw.exact = XtVaCreateManagedWidget |
722 |
("exact",commandWidgetClass,form, |
723 |
XtNfromVert,self->iw.face, |
724 |
XtNresize,True, |
725 |
XtNadjust,False, |
726 |
NULL); |
727 |
XtAddCallback(self->iw.exact,XtNcallback,AttrDumpCb,(XtPointer)self); |
728 |
|
729 |
/*** inventory ***/ |
730 |
view = XtVaCreateManagedWidget |
731 |
("inventory",viewportWidgetClass,form, |
732 |
XtNfromVert,self->iw.name, |
733 |
XtNfromHoriz,self->iw.face, |
734 |
NULL); |
735 |
|
736 |
self->iw.inv = XtVaCreateManagedWidget |
737 |
("list",crListWidgetClass,view, |
738 |
XtNpackage, self, |
739 |
XtNnext, AttrInventoryNext, |
740 |
NULL); |
741 |
XtAddCallback(self->iw.inv,XtNselectCallback,AttrInventorySelectCb, |
742 |
(XtPointer)self); |
743 |
XtAddCallback(self->iw.inv,XtNinsertCallback,InsertCb, |
744 |
(XtPointer)self); |
745 |
XtAddCallback(self->iw.inv,XtNdeleteCallback,DeleteCb, |
746 |
(XtPointer)self); |
747 |
|
748 |
/*** multi ***/ |
749 |
view1 = XtVaCreateManagedWidget |
750 |
("view",viewportWidgetClass,form, |
751 |
/*XtNallowVert,True,*/ |
752 |
XtNforceBars,True, |
753 |
XtNfromVert,self->iw.exact, |
754 |
NULL); |
755 |
pane = XtVaCreateManagedWidget |
756 |
("pane",boxWidgetClass,view1, |
757 |
XtNorientation,XtorientVertical, |
758 |
NULL); |
759 |
|
760 |
/*** variable setting ***/ |
761 |
AttrVarLayout(self,parent); |
762 |
|
763 |
self->iw.msg = XtVaCreateManagedWidget |
764 |
("msg",asciiTextWidgetClass,form, |
765 |
XtNtype,XawAsciiString, |
766 |
XtNeditType,XawtextEdit, |
767 |
XtNfromHoriz,NULL, |
768 |
XtNfromVert,view1, |
769 |
NULL); |
770 |
|
771 |
|
772 |
self->iw.vars = XtVaCreateManagedWidget |
773 |
("vars",commandWidgetClass,form, |
774 |
XtNfromVert,self->iw.msg, |
775 |
NULL); |
776 |
XtAddCallback(self->iw.vars,XtNcallback,AttrVarGetCb,(XtPointer)self); |
777 |
self->iw.var = XtVaCreateManagedWidget |
778 |
("var",asciiTextWidgetClass,form, |
779 |
XtNfromHoriz,self->iw.vars, |
780 |
XtNfromVert,self->iw.msg, |
781 |
XtNtype,XawAsciiString, |
782 |
XtNeditType,XawtextEdit, |
783 |
NULL); |
784 |
|
785 |
/*** reponses ***/ |
786 |
ok = XtVaCreateManagedWidget |
787 |
("ok",commandWidgetClass,form, |
788 |
XtNfromVert,self->iw.vars, |
789 |
NULL); |
790 |
XtAddCallback(ok,XtNcallback,AttrOkCb,(XtPointer)self); |
791 |
apply = XtVaCreateManagedWidget |
792 |
("apply",commandWidgetClass,form, |
793 |
XtNfromVert,self->iw.vars, |
794 |
XtNfromHoriz,ok, |
795 |
NULL); |
796 |
XtAddCallback(apply,XtNcallback,AttrApplyCb,(XtPointer)self); |
797 |
cancel = XtVaCreateManagedWidget |
798 |
("cancel",commandWidgetClass,form, |
799 |
XtNfromVert,self->iw.vars, |
800 |
XtNfromHoriz,apply, |
801 |
NULL); |
802 |
XtAddCallback(cancel,XtNcallback,AttrCancelCb,(XtPointer)self); |
803 |
|
804 |
AttrTagsCreate(self,pane); |
805 |
} |
806 |
|
807 |
/* |
808 |
* - create object attribute editor from given object |
809 |
* - change values in future of given object |
810 |
* - struct Attr don't have to be initialized, but have to be |
811 |
* allocated anyway. |
812 |
* - create widgets & popup window |
813 |
*/ |
814 |
Attr AttrCreate(char *name, App app, object *ob, |
815 |
AttrDef *desc, unsigned long flags, Edit edit) |
816 |
{ |
817 |
Attr self = (Attr) XtMalloc (sizeof(struct _Attr)); |
818 |
|
819 |
if (ob->head) |
820 |
ob = ob->head; |
821 |
self->op = ob; |
822 |
self->app = app; |
823 |
self->client = edit; |
824 |
self->attr = NULL; |
825 |
|
826 |
self->desc = desc; |
827 |
AppLayout (self, self->app->shell, name); |
828 |
AttrChange(self,self->op, flags, self->client); |
829 |
|
830 |
self->dump = CnvBrowseCreate("dump", self->app->shell, NULL); |
831 |
XtPopup(self->shell,XtGrabNone); |
832 |
self->isup = True; |
833 |
return self; |
834 |
} |
835 |
|
836 |
/* |
837 |
* change object to another |
838 |
*/ |
839 |
void AttrChange(Attr self,object *ob, unsigned long flags, Edit edit) |
840 |
{ |
841 |
char buf[BUFSIZ]; |
842 |
int i, mask = 1; |
843 |
|
844 |
if (!self) |
845 |
return; |
846 |
|
847 |
if (self->attr) |
848 |
AttrDestroy (self->attr); |
849 |
|
850 |
if (ob && ob->head) |
851 |
ob = ob->head; |
852 |
self->op = ob; |
853 |
|
854 |
if(!ob) { |
855 |
AttrReset(self); |
856 |
XtVaSetValues(self->shell, |
857 |
XtNtitle,"", |
858 |
NULL); |
859 |
return; |
860 |
} |
861 |
|
862 |
self->flags = flags; |
863 |
|
864 |
/*** name ***/ |
865 |
XtVaSetValues(self->iw.name, |
866 |
XtNstring,self->op->name, |
867 |
NULL); |
868 |
|
869 |
/*** object ***/ |
870 |
XtVaSetValues(self->iw.face, |
871 |
XtNobject,self->op, |
872 |
NULL); |
873 |
|
874 |
/*** message ***/ |
875 |
XtVaSetValues(self->iw.msg, |
876 |
XtNstring,self->op->msg, |
877 |
NULL); |
878 |
|
879 |
/*** inventory ***/ |
880 |
XtVaSetValues(self->iw.inv, |
881 |
XtNpackage,self, |
882 |
NULL); |
883 |
|
884 |
/* get attribute value */ |
885 |
for (i = 0; self->desc[i].label; i++, mask <<= 1) |
886 |
if(self->flags & mask) { |
887 |
self->desc[i].getValue (ob, buf, (XtPointer) self->client); |
888 |
if (self->desc[i].type == TypeString) { |
889 |
XtVaSetValues(self->tags[i].value, |
890 |
XtNstring, buf, |
891 |
NULL); |
892 |
} else if (self->desc[i].type == TypeToggle) { |
893 |
XtVaSetValues(self->tags[i].value, |
894 |
XtNstate, *buf ? TRUE : FALSE, |
895 |
NULL); |
896 |
} |
897 |
} |
898 |
|
899 |
/*** update ***/ |
900 |
for(i=0; self->desc[i].label; i++) { |
901 |
XtUnmanageChild(self->tags[i].cont); |
902 |
} |
903 |
for(i=0; self->desc[i].label; i++) { |
904 |
if(self->flags & (1 << i)) { |
905 |
XtManageChild(self->tags[i].cont); |
906 |
} |
907 |
} |
908 |
sprintf(buf,"Attr: %s",self->op->name); |
909 |
XtVaSetValues(self->shell, |
910 |
XtNtitle,buf, |
911 |
XtNiconName,buf, |
912 |
NULL); |
913 |
self->modified = False; |
914 |
} |
915 |
|
916 |
static void AttrReset(Attr self) |
917 |
{ |
918 |
int i; |
919 |
debug0("Attr-Reset()\n"); |
920 |
/*** name ***/ |
921 |
XtVaSetValues(self->iw.name, |
922 |
XtNstring,NULL, |
923 |
NULL); |
924 |
/*** object ***/ |
925 |
XtVaSetValues(self->iw.face, |
926 |
XtNobject,NULL, |
927 |
NULL); |
928 |
/*** message ***/ |
929 |
XtVaSetValues(self->iw.msg, |
930 |
XtNstring,NULL, |
931 |
NULL); |
932 |
/*** inventory ***/ |
933 |
XtVaSetValues(self->iw.inv, |
934 |
XtNpackage,self, |
935 |
NULL); |
936 |
|
937 |
for(i=0; self->desc[i].label; i++) { |
938 |
XtUnmanageChild(self->tags[i].cont); |
939 |
} |
940 |
} |
941 |
|
942 |
/* |
943 |
* popdown window & destroy widgets |
944 |
*/ |
945 |
void AttrDestroy(Attr self) |
946 |
{ |
947 |
Attr tmp2; |
948 |
|
949 |
if (self->attr) |
950 |
AttrDestroy (self->attr); |
951 |
XtDestroyWidget(self->shell); |
952 |
XtFree((char*)self->tags); |
953 |
self->isup = False; |
954 |
CnvBrowseDestroy(self->dump); |
955 |
|
956 |
/* |
957 |
* dirty part: |
958 |
* here we find out to what part this window belongs to. |
959 |
* it may be: |
960 |
* - Attr of Look in App |
961 |
* - Attr of other Attr (inventory) |
962 |
*/ |
963 |
|
964 |
if (self == self->app->attr) |
965 |
self->app->attr = NULL; |
966 |
else { |
967 |
for (tmp2 = self->app->attr; tmp2; tmp2 = tmp2->attr) |
968 |
if (self == tmp2->attr) { |
969 |
tmp2->attr = NULL; |
970 |
break; |
971 |
} |
972 |
#ifdef DEBUG |
973 |
if (!tmp2) |
974 |
debug0 ("Cannot find origin of Attr!!\n"); |
975 |
#endif |
976 |
} |
977 |
XtFree((char*)self); |
978 |
} |
979 |
|
980 |
/* |
981 |
* member: store information from edited widget structure |
982 |
* to object structure |
983 |
*/ |
984 |
void AttrApply(Attr self) |
985 |
{ |
986 |
String str,var; |
987 |
object *ob; |
988 |
char buf[BUFSIZ]; |
989 |
int len, mask,set_all=1; |
990 |
size_t i; |
991 |
|
992 |
/* check out, that object exist */ |
993 |
if(!self->op) { |
994 |
return; |
995 |
} |
996 |
|
997 |
for(ob = self->op; ob && set_all; ob = ob->more) { |
998 |
/*** variable ***/ |
999 |
XtVaGetValues(self->iw.var, |
1000 |
XtNstring,&var, |
1001 |
NULL); |
1002 |
if(var && *var) { |
1003 |
debug1("AttrApply(), %s\n",var); |
1004 |
|
1005 |
/* This is a pretty gross hack, but somewhat necessary. Otherwise, |
1006 |
* all pieces of a multisquare monster will get the treasure, which |
1007 |
* is really not what we want. |
1008 |
*/ |
1009 |
if (!strncmp(var, "randomitems", 11)) set_all=0; |
1010 |
for (i = 0; i < ALLOWED_VARIABLES; i++) |
1011 |
if (!strncmp (allowed_variables[i], var, |
1012 |
strlen(allowed_variables[i]))) { |
1013 |
if (set_variable(ob,var) == -1) { |
1014 |
sprintf(buf,"%s: no such variable",var); |
1015 |
CnvNotify(buf,"Continue",NULL); |
1016 |
} |
1017 |
break; |
1018 |
} |
1019 |
if (i >= ALLOWED_VARIABLES) { |
1020 |
sprintf(buf,"%s: cannot set variable",var); |
1021 |
CnvNotify(buf,"Continue",NULL); |
1022 |
} |
1023 |
} |
1024 |
/*** name ***/ |
1025 |
XtVaGetValues(self->iw.name, |
1026 |
XtNstring,&str, |
1027 |
NULL); |
1028 |
if(ob->name) free_string(ob->name); |
1029 |
ob->name = add_string(str); |
1030 |
|
1031 |
/*** message ***/ |
1032 |
XtVaGetValues(self->iw.msg, |
1033 |
XtNstring,&str, |
1034 |
NULL); |
1035 |
|
1036 |
if(self->op->msg) free_string(self->op->msg); |
1037 |
if((len = strlen(str))) { |
1038 |
if(str[len-1] != '\n') str[len-1] = '\n'; /*** kludge ***/ |
1039 |
self->op->msg = add_string(str); |
1040 |
} else { |
1041 |
self->op->msg = NULL; |
1042 |
} |
1043 |
|
1044 |
/* set individual attribute value */ |
1045 |
for (i = 0, mask = 1; self->desc[i].label; i++, mask <<= 1) { |
1046 |
if(self->flags & mask) { |
1047 |
if (self->desc[i].type == TypeString) { |
1048 |
XtVaGetValues(self->tags[i].value, XtNstring, &str, NULL); |
1049 |
self->desc[i].putValue (ob, str, (XtPointer)self->client); |
1050 |
} else if (self->desc[i].type == TypeToggle) { |
1051 |
Boolean tmp; |
1052 |
XtVaGetValues(self->tags[i].value, XtNstate, &tmp, NULL); |
1053 |
*str = tmp ? ~0 : 0; |
1054 |
self->desc[i].putValue (ob, str, (XtPointer)self->client); |
1055 |
} |
1056 |
} |
1057 |
} |
1058 |
} /* for all parts of the object */ |
1059 |
|
1060 |
/*** clear variables ***/ |
1061 |
XtVaSetValues(self->iw.var,XtNstring,NULL,NULL); |
1062 |
|
1063 |
/*** update ***/ |
1064 |
AppUpdate (self->app); |
1065 |
|
1066 |
self->modified = True; |
1067 |
/*self->client->modified = True;*/ |
1068 |
EditModified(self->client); |
1069 |
} |
1070 |
|
1071 |
|
1072 |
/*** end of Attr.c ***/ |