1 /*
2 * Author: William Chia-Wei Cheng (bill.cheng@acm.org)
3 *
4 * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5 *
6 * This file may be distributed under the terms of the Q Public License
7 * as defined by Trolltech AS of Norway and appearing in the file
8 * LICENSE.QPL included in the packaging of this file.
9 *
10 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12 * PURPOSE. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * @(#)$Header: /mm2/home/cvs/bc-src/tgif/group.c,v 1.7 2011/05/16 16:21:57 william Exp $
19 */
20
21 #define _INCLUDE_FROM_GROUP_C_
22
23 #include "tgifdefs.h"
24
25 #include "attr.e"
26 #include "choice.e"
27 #include "cmd.e"
28 #include "dialog.e"
29 #include "drawing.e"
30 #include "dup.e"
31 #include "file.e"
32 #include "group.e"
33 #include "mark.e"
34 #include "msg.e"
35 #include "obj.e"
36 #include "page.e"
37 #include "select.e"
38 #include "setup.e"
39 #include "strtbl.e"
40
41 int gnDeleteAttrsWhileUngrouping=FALSE;
42
JustCreateGroupObj()43 struct ObjRec *JustCreateGroupObj()
44 {
45 struct GroupRec *group_ptr=NULL;
46 struct ObjRec *obj_ptr=NULL;
47
48 group_ptr = (struct GroupRec *)malloc(sizeof(struct GroupRec));
49 if (group_ptr == NULL) FailAllocMessage();
50 memset(group_ptr, 0, sizeof(struct GroupRec));
51 group_ptr->first = NULL;
52 group_ptr->last = NULL;
53 group_ptr->rotate = ROTATE0;
54 group_ptr->flip = NO_FLIP;
55 group_ptr->deck_index = (-1);
56 group_ptr->pin_connected = 0;
57 group_ptr->first_conn = group_ptr->last_conn = NULL;
58 obj_ptr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
59 if (obj_ptr == NULL) FailAllocMessage();
60 memset(obj_ptr, 0, sizeof(struct ObjRec));
61 obj_ptr->x = 0;
62 obj_ptr->y = 0;
63 obj_ptr->id = objId++;
64 obj_ptr->locked = FALSE;
65 obj_ptr->type = OBJ_GROUP;
66 obj_ptr->bbox.ltx = 0;
67 obj_ptr->bbox.lty = 0;
68 obj_ptr->bbox.rbx = 0;
69 obj_ptr->bbox.rby = 0;
70 obj_ptr->obbox.ltx = 0;
71 obj_ptr->obbox.lty = 0;
72 obj_ptr->obbox.rbx = 0;
73 obj_ptr->obbox.rby = 0;
74 obj_ptr->detail.r = group_ptr;
75 obj_ptr->fattr = obj_ptr->lattr = NULL;
76 obj_ptr->ctm = NULL;
77 obj_ptr->invisible = FALSE;
78
79 return obj_ptr;
80 }
81
CreateGroupObj(TopObjPtr,BotObjPtr)82 void CreateGroupObj(TopObjPtr, BotObjPtr)
83 struct ObjRec *TopObjPtr, *BotObjPtr;
84 {
85 struct ObjRec *obj_ptr=JustCreateGroupObj();
86 struct GroupRec *group_ptr=obj_ptr->detail.r;
87
88 group_ptr->first = TopObjPtr;
89 group_ptr->last = BotObjPtr;
90 obj_ptr->x = selObjLtX; /* note: selLtX, selLtY are absolute */
91 obj_ptr->y = selObjLtY;
92 obj_ptr->bbox.ltx = selLtX;
93 obj_ptr->bbox.lty = selLtY;
94 obj_ptr->bbox.rbx = selRbX;
95 obj_ptr->bbox.rby = selRbY;
96 obj_ptr->obbox.ltx = selObjLtX;
97 obj_ptr->obbox.lty = selObjLtY;
98 obj_ptr->obbox.rbx = selObjRbX;
99 obj_ptr->obbox.rby = selObjRbY;
100 if (numObjLocked > 0) obj_ptr->locked = TRUE;
101 AddObj(NULL, topObj, obj_ptr);
102 }
103
SaveGroupObj(FP,ObjPtr,Level)104 void SaveGroupObj(FP, ObjPtr, Level)
105 FILE *FP;
106 struct ObjRec *ObjPtr;
107 int Level;
108 {
109 if (fprintf(FP, "group([\n") == EOF) writeFileFailed = TRUE;
110 Save(FP, ObjPtr->detail.r->last, Level+1, INVALID);
111 if (fprintf(FP, "],\n") == EOF) writeFileFailed = TRUE;
112 if (fprintf(FP, "%1d,%1d,%1d,", ObjPtr->id, ObjPtr->locked,
113 ObjPtr->invisible) == EOF) {
114 writeFileFailed = TRUE;
115 }
116 if (serializingFile) SaveCreatorID(FP, ObjPtr, "\t");
117 SaveAttrs(FP, ObjPtr->lattr);
118 if (fprintf(FP, ")") == EOF) writeFileFailed = TRUE;
119 }
120
SaveCompObj(FP,ObjPtr,Level)121 void SaveCompObj(FP, ObjPtr, Level)
122 FILE *FP;
123 struct ObjRec *ObjPtr;
124 int Level;
125 {
126 if (fprintf(FP, "sym([\n") == EOF) writeFileFailed = TRUE;
127 Save(FP, ObjPtr->detail.r->last, Level+1, INVALID);
128 if (fprintf(FP, "],\n") == EOF) writeFileFailed = TRUE;
129 if (fprintf(FP, "%1d,%1d,%1d,", ObjPtr->id, ObjPtr->locked,
130 ObjPtr->invisible) == EOF) {
131 writeFileFailed = TRUE;
132 }
133 if (serializingFile) SaveCreatorID(FP, ObjPtr, "\t");
134 SaveAttrs(FP, ObjPtr->lattr);
135 if (fprintf(FP, ")") == EOF) writeFileFailed = TRUE;
136 }
137
SaveIconObj(FP,ObjPtr,Level)138 void SaveIconObj(FP, ObjPtr, Level)
139 FILE *FP;
140 struct ObjRec *ObjPtr;
141 int Level;
142 {
143 if (fprintf(FP, "icon([\n") == EOF) writeFileFailed = TRUE;
144 Save(FP, ObjPtr->detail.r->last, Level+1, INVALID);
145 if (fprintf(FP, "],\n") == EOF) writeFileFailed = TRUE;
146 if (fprintf(FP, "\"%s\",%1d,%1d,%1d,%1d,%1d,",
147 ObjPtr->detail.r->s, ObjPtr->id, ObjPtr->detail.r->rotate,
148 ObjPtr->detail.r->flip, ObjPtr->locked, ObjPtr->invisible) == EOF) {
149 writeFileFailed = TRUE;
150 }
151 if (serializingFile) SaveCreatorID(FP, ObjPtr, "\t");
152 SaveAttrs(FP, ObjPtr->lattr);
153 if (fprintf(FP, ")") == EOF) writeFileFailed = TRUE;
154 }
155
SavePinObj(FP,ObjPtr,Level)156 void SavePinObj(FP, ObjPtr, Level)
157 FILE *FP;
158 struct ObjRec *ObjPtr;
159 int Level;
160 {
161 if (fprintf(FP, "pin([\n") == EOF) writeFileFailed = TRUE;
162 Save(FP, ObjPtr->detail.r->last, Level+1, INVALID);
163 if (fprintf(FP, "],\n") == EOF) writeFileFailed = TRUE;
164 /*
165 * Need to check for pins.
166 * Need to handle the case where connection objects need to be dupped!
167 */
168 if (fprintf(FP, "\"%s\",%1d,%1d,%1d,%1d,%1d,%1d,",
169 ObjPtr->detail.r->s, ObjPtr->id, ObjPtr->detail.r->rotate,
170 ObjPtr->detail.r->flip, ObjPtr->locked, ObjPtr->invisible,
171 ObjPtr->detail.r->pin_connected) == EOF) {
172 writeFileFailed = TRUE;
173 }
174 if (serializingFile) SaveCreatorID(FP, ObjPtr, "\t");
175 SaveAttrs(FP, ObjPtr->lattr);
176 if (fprintf(FP, ")") == EOF) writeFileFailed = TRUE;
177 }
178
179 static int gnPinWarning=FALSE;
180
181 #define GETGROUPVALUE(val,name) ScanValue("%d", &(val), name, "group")
182 #define GETSYMVALUE(val,name) ScanValue("%d", &(val), name, "sym")
183 #define GETICONVALUE(val,name) ScanValue("%d", &(val), name, "icon")
184 #define GETPINVALUE(val,name) ScanValue("%d", &(val), name, "pin")
185
ReadGroupObj(FP,ObjType,ObjPtr)186 void ReadGroupObj(FP, ObjType, ObjPtr)
187 FILE *FP;
188 int ObjType;
189 struct ObjRec **ObjPtr;
190 {
191 struct GroupRec *group_ptr;
192 struct ObjRec *top_obj=NULL, *bot_obj=NULL, *obj_ptr;
193 int ltx, lty, rbx, rby, id=0, locked=FALSE;
194 int obj_ltx, obj_lty, obj_rbx, obj_rby, rotate=0, flip=0;
195 int invisible=FALSE, pin_connected=0;
196 char line[MAXSTRING+1], *s, *s1, tmp_str[MAXSTRING+1];
197
198 *ObjPtr = NULL;
199 while (ReadObj(FP, &obj_ptr)) {
200 if (obj_ptr == NULL) return;
201
202 obj_ptr->next = top_obj;
203 if (top_obj == NULL) {
204 bot_obj = obj_ptr;
205 } else {
206 top_obj->prev = obj_ptr;
207 }
208 top_obj = obj_ptr;
209 }
210 if (top_obj == NULL) return;
211
212 if (fileVersion <= 20 && (ObjType==OBJ_GROUP || ObjType==OBJ_SYM)) {
213 id = objId++;
214 } else {
215 if (fgets(line, MAXSTRING, FP) == NULL) return;
216 scanLineNum++;
217
218 switch (ObjType) {
219 case OBJ_GROUP:
220 InitScan(line, "\t\n, []");
221 if (fileVersion <= 25) {
222 if (GETGROUPVALUE(id, "id") == INVALID) return;
223 } else if (fileVersion <= 32) {
224 if (GETGROUPVALUE(id, "id") == INVALID ||
225 GETGROUPVALUE(locked, "locked") == INVALID) {
226 return;
227 }
228 } else {
229 if (GETGROUPVALUE(id, "id") == INVALID ||
230 GETGROUPVALUE(locked, "locked") == INVALID ||
231 GETGROUPVALUE(invisible, "invisible") == INVALID) {
232 return;
233 }
234 }
235 if (id >= objId) objId = id+1;
236 break;
237 case OBJ_SYM:
238 InitScan(line, "\t\n, []");
239 if (fileVersion <= 25) {
240 if (GETSYMVALUE(id, "id") == INVALID) return;
241 } else if (fileVersion <= 32) {
242 if (GETSYMVALUE(id, "id") == INVALID ||
243 GETSYMVALUE(locked, "locked") == INVALID) {
244 return;
245 }
246 } else {
247 if (GETSYMVALUE(id, "id") == INVALID ||
248 GETSYMVALUE(locked, "locked") == INVALID ||
249 GETSYMVALUE(invisible, "invisible") == INVALID) {
250 return;
251 }
252 }
253 if (id >= objId) objId = id+1;
254 break;
255 case OBJ_ICON:
256 strcpy(tmp_str, FindChar((int)'"', line));
257 s = FindChar((int)'"', tmp_str);
258 if (fileVersion == INVALID) return;
259
260 if (fileVersion <= 12) {
261 s1 = FindChar((int)',', s);
262 InitScan(s1, "\t\n, ");
263 if (GETICONVALUE(id, "id") == INVALID) return;
264 } else if (fileVersion <= 25) {
265 s1 = FindChar((int)',', s);
266 InitScan(s1, "\t\n, ");
267 if (GETICONVALUE(id, "id") == INVALID ||
268 GETICONVALUE(rotate, "rotation") == INVALID ||
269 GETICONVALUE(flip, "flip") == INVALID) {
270 return;
271 }
272 } else if (fileVersion <= 32) {
273 s1 = FindChar((int)',', s);
274 InitScan(s1, "\t\n, ");
275 if (GETICONVALUE(id, "id") == INVALID ||
276 GETICONVALUE(rotate, "rotation") == INVALID ||
277 GETICONVALUE(flip, "flip") == INVALID ||
278 GETICONVALUE(locked, "locked") == INVALID) {
279 return;
280 }
281 } else {
282 s1 = FindChar((int)',', s);
283 InitScan(s1, "\t\n, ");
284 if (GETICONVALUE(id, "id") == INVALID ||
285 GETICONVALUE(rotate, "rotation") == INVALID ||
286 GETICONVALUE(flip, "flip") == INVALID ||
287 GETICONVALUE(locked, "locked") == INVALID ||
288 GETICONVALUE(invisible, "invisible") == INVALID) {
289 return;
290 }
291 }
292 if (id >= objId) objId = id+1;
293 *(--s) = '\0';
294 break;
295 case OBJ_PIN:
296 strcpy(tmp_str, FindChar((int)'"', line));
297 s = FindChar((int)'"', tmp_str);
298 if (fileVersion == INVALID) return;
299
300 if (fileVersion >= 34) {
301 s1 = FindChar((int)',', s);
302 InitScan(s1, "\t\n, ");
303 /*
304 * Need to check for pins.
305 * Need to handle the case where connection objects need to be dupped!
306 */
307 if (GETPINVALUE(id, "id") == INVALID ||
308 GETPINVALUE(rotate, "rotation") == INVALID ||
309 GETPINVALUE(flip, "flip") == INVALID ||
310 GETPINVALUE(locked, "locked") == INVALID ||
311 GETPINVALUE(invisible, "invisible") == INVALID ||
312 GETPINVALUE(pin_connected, "pin_connected") == INVALID) {
313 return;
314 }
315 }
316 if (id >= objId) objId = id+1;
317 *(--s) = '\0';
318 if (!gnPinWarning) {
319 gnPinWarning = TRUE;
320 strcpy(gszMsgBox, TgLoadString(STID_WARN_PIN_NOT_SUPPORTED));
321 if (PRTGIF) {
322 fprintf(stderr, "%s\n", gszMsgBox);
323 } else {
324 MsgBox(gszMsgBox, TOOL_NAME, STOP_MB);
325 }
326 }
327 break;
328 }
329 }
330
331 *ObjPtr = (struct ObjRec *)malloc(sizeof(struct ObjRec));
332 if (*ObjPtr == NULL) FailAllocMessage();
333 memset(*ObjPtr, 0, sizeof(struct ObjRec));
334
335 top_obj->prev = NULL;
336
337 group_ptr = (struct GroupRec *)malloc(sizeof(struct GroupRec));
338 if (group_ptr == NULL) FailAllocMessage();
339 memset(group_ptr, 0, sizeof(struct GroupRec));
340 group_ptr->first = top_obj;
341 group_ptr->last = bot_obj;
342 group_ptr->rotate = rotate;
343 group_ptr->flip = flip;
344 group_ptr->deck_index = (-1);
345 group_ptr->pin_connected = pin_connected;
346 group_ptr->first_conn = group_ptr->last_conn = NULL;
347 if (ObjType == OBJ_ICON || ObjType == OBJ_PIN) {
348 strcpy(group_ptr->s, tmp_str);
349 }
350 ltx = top_obj->bbox.ltx;
351 lty = top_obj->bbox.lty;
352 rbx = top_obj->bbox.rbx;
353 rby = top_obj->bbox.rby;
354 obj_ltx = top_obj->obbox.ltx;
355 obj_lty = top_obj->obbox.lty;
356 obj_rbx = top_obj->obbox.rbx;
357 obj_rby = top_obj->obbox.rby;
358 for (obj_ptr = top_obj->next; obj_ptr != NULL; obj_ptr = obj_ptr->next) {
359 if (obj_ptr->bbox.ltx < ltx) ltx = obj_ptr->bbox.ltx;
360 if (obj_ptr->bbox.lty < lty) lty = obj_ptr->bbox.lty;
361 if (obj_ptr->bbox.rbx > rbx) rbx = obj_ptr->bbox.rbx;
362 if (obj_ptr->bbox.rby > rby) rby = obj_ptr->bbox.rby;
363 if (obj_ptr->obbox.ltx < obj_ltx) obj_ltx = obj_ptr->obbox.ltx;
364 if (obj_ptr->obbox.lty < obj_lty) obj_lty = obj_ptr->obbox.lty;
365 if (obj_ptr->obbox.rbx > obj_rbx) obj_rbx = obj_ptr->obbox.rbx;
366 if (obj_ptr->obbox.rby > obj_rby) obj_rby = obj_ptr->obbox.rby;
367 }
368
369 (*ObjPtr)->x = obj_ltx;
370 (*ObjPtr)->y = obj_lty;
371 (*ObjPtr)->dirty = FALSE;
372 (*ObjPtr)->id = id;
373 (*ObjPtr)->locked = locked;
374 (*ObjPtr)->type = ObjType;
375 (*ObjPtr)->bbox.ltx = ltx;
376 (*ObjPtr)->bbox.lty = lty;
377 (*ObjPtr)->bbox.rbx = rbx;
378 (*ObjPtr)->bbox.rby = rby;
379 (*ObjPtr)->obbox.ltx = obj_ltx;
380 (*ObjPtr)->obbox.lty = obj_lty;
381 (*ObjPtr)->obbox.rbx = obj_rbx;
382 (*ObjPtr)->obbox.rby = obj_rby;
383 (*ObjPtr)->detail.r = group_ptr;
384 (*ObjPtr)->ctm = NULL;
385 (*ObjPtr)->invisible = invisible;
386 }
387
FreeGroupObj(ObjPtr)388 void FreeGroupObj(ObjPtr)
389 struct ObjRec *ObjPtr;
390 {
391 register struct ObjRec *ptr, *next_obj;
392
393 for (ptr=ObjPtr->detail.r->first; ptr != NULL; ptr=next_obj) {
394 next_obj = ptr->next;
395 FreeObj(ptr);
396 }
397 free(ObjPtr->detail.r);
398 free(ObjPtr);
399 }
400
UngroupObj(ObjPtr,TopSelPtr,BotSelPtr)401 void UngroupObj(ObjPtr, TopSelPtr, BotSelPtr)
402 struct ObjRec *ObjPtr;
403 struct SelRec **TopSelPtr, **BotSelPtr;
404 /* ungroup the grouped object ObjPtr to a list of objects */
405 /* when returns, a list of select pointers will be created, */
406 /* *TopSelPtr will point to the top of the list, and */
407 /* *BotSelPtr will point to the bottom of the list. */
408 {
409 struct ObjRec *obj_ptr=ObjPtr->detail.r->last;
410
411 for ( ; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
412 AddObjIntoSel(obj_ptr, NULL, *TopSelPtr, TopSelPtr, BotSelPtr);
413 }
414 (*TopSelPtr)->prev = NULL;
415 }
416
417 static
NoObjToUngroup(pn_force_ungroup)418 int NoObjToUngroup(pn_force_ungroup)
419 int *pn_force_ungroup;
420 {
421 struct SelRec *sel_ptr=NULL;
422 int every_obj_is_sym_or_icon=TRUE;
423
424 if (pn_force_ungroup != NULL && topSel != NULL && topSel == botSel) {
425 int obj_type=topSel->obj->type;
426
427 *pn_force_ungroup = FALSE;
428 if (obj_type==OBJ_ICON || obj_type==OBJ_SYM) {
429 /*
430 * Need to check for pins.
431 */
432 if (MsgBox(TgLoadString(STID_ONE_SIMPLE_GROUP_UNGROUP_ANY), TOOL_NAME,
433 YNC_MB) == MB_ID_YES) {
434 *pn_force_ungroup = TRUE;
435 return FALSE;
436 }
437 return TRUE;
438 }
439 }
440 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
441 int obj_type=sel_ptr->obj->type;
442
443 if (obj_type == OBJ_GROUP) {
444 return FALSE;
445 } else if (obj_type==OBJ_ICON || obj_type==OBJ_SYM) {
446 /*
447 * Need to check for pins.
448 */
449 } else {
450 every_obj_is_sym_or_icon = FALSE;
451 }
452 }
453 if (every_obj_is_sym_or_icon) {
454 if (MsgBox(TgLoadString(STID_ALL_SIMPLE_GROUP_UNGROUP_ANY), TOOL_NAME,
455 YNC_MB) == MB_ID_YES) {
456 *pn_force_ungroup = TRUE;
457 return FALSE;
458 }
459 }
460 return TRUE;
461 }
462
UngroupSelObj(highlight,record_cmd)463 void UngroupSelObj(highlight, record_cmd)
464 int highlight, record_cmd;
465 {
466 struct SelRec *sel_ptr=NULL, *next_sel=NULL;
467 struct ObjRec *obj_ptr=NULL;
468 int sel_ltx, sel_lty, sel_rbx, sel_rby;
469 int changed=FALSE, force_ungroup_single_obj=FALSE;
470
471 if (topSel==NULL || NoObjToUngroup(&force_ungroup_single_obj)) return;
472
473 sel_ltx = selLtX; sel_lty = selLtY;
474 sel_rbx = selRbX; sel_rby = selRbY;
475
476 if (highlight) HighLightReverse();
477 if (record_cmd) StartCompositeCmd();
478 if (force_ungroup_single_obj) {
479 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
480 struct AttrRec *attr_ptr=NULL;
481
482 obj_ptr = sel_ptr->obj;
483
484 switch (obj_ptr->type) {
485 case OBJ_ICON:
486 PrepareToReplaceAnObj(obj_ptr);
487 obj_ptr->type = OBJ_GROUP;
488 attr_ptr = obj_ptr->fattr;
489 for ( ; attr_ptr != NULL; attr_ptr=attr_ptr->next) {
490 attr_ptr->inherited = FALSE;
491 }
492 AdjObjBBox(obj_ptr);
493 RecordReplaceAnObj(obj_ptr);
494 break;
495 case OBJ_SYM:
496 PrepareToReplaceAnObj(obj_ptr);
497 obj_ptr->type = OBJ_GROUP;
498 AdjObjBBox(obj_ptr);
499 RecordReplaceAnObj(obj_ptr);
500 break;
501 case OBJ_PIN:
502 /*
503 * Need to check for pins.
504 */
505 break;
506 default: break;
507 }
508 }
509 }
510 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=next_sel) {
511 next_sel = sel_ptr->next;
512 obj_ptr = sel_ptr->obj;
513 if (obj_ptr->type == OBJ_GROUP) {
514 int count;
515 struct SelRec *tmp_sel_ptr, *tmp_top_sel=NULL, *tmp_bot_sel=NULL;
516
517 changed = TRUE;
518 if (record_cmd) PrepareToReplaceAnObj(obj_ptr);
519
520 UngroupObj(obj_ptr, &tmp_top_sel, &tmp_bot_sel);
521 if (gnDeleteAttrsWhileUngrouping) {
522 DelAllAttrs(obj_ptr->fattr);
523 } else {
524 DetachGroupAttrs(obj_ptr, &tmp_top_sel, &tmp_bot_sel);
525 }
526 obj_ptr->detail.r->first->prev = obj_ptr->prev;
527 if (obj_ptr->prev == NULL) {
528 curPage->top = topObj = obj_ptr->detail.r->first;
529 } else {
530 obj_ptr->prev->next = obj_ptr->detail.r->first;
531 }
532 obj_ptr->detail.r->last->next = obj_ptr->next;
533 if (obj_ptr->next == NULL) {
534 curPage->bot = botObj = obj_ptr->detail.r->last;
535 } else {
536 obj_ptr->next->prev = obj_ptr->detail.r->last;
537 }
538 count = 0;
539 for (tmp_sel_ptr=tmp_top_sel; tmp_sel_ptr!=NULL;
540 tmp_sel_ptr=tmp_sel_ptr->next) {
541 count++;
542 }
543 if (record_cmd) {
544 RecordCmd(CMD_ONE_TO_MANY, NULL, tmp_top_sel, tmp_bot_sel, count);
545 }
546 tmp_top_sel->prev = sel_ptr->prev;
547 if (sel_ptr->prev == NULL) {
548 topSel = tmp_top_sel;
549 } else {
550 sel_ptr->prev->next = tmp_top_sel;
551 }
552 tmp_bot_sel->next = sel_ptr->next;
553 if (sel_ptr->next == NULL) {
554 botSel = tmp_bot_sel;
555 } else {
556 sel_ptr->next->prev = tmp_bot_sel;
557 }
558 free(sel_ptr);
559 /*
560 * What about obj_ptr->detail.r->first_conn and
561 * obj_ptr->detail.r->last_conn?
562 */
563 free(obj_ptr->detail.r);
564 free(obj_ptr);
565 }
566 }
567 if (record_cmd) EndCompositeCmd();
568 if (changed) {
569 UpdSelBBox();
570 RedrawAreas(botObj,
571 sel_ltx-GRID_ABS_SIZE(1), sel_lty-GRID_ABS_SIZE(1),
572 sel_rbx+GRID_ABS_SIZE(1), sel_rby+GRID_ABS_SIZE(1),
573 selLtX-GRID_ABS_SIZE(1), selLtY-GRID_ABS_SIZE(1),
574 selRbX+GRID_ABS_SIZE(1), selRbY+GRID_ABS_SIZE(1));
575 SetFileModified(TRUE);
576 justDupped = FALSE;
577 Msg(TgLoadString(STID_SEL_OBJ_ARE_UNGROUPED));
578 }
579 if (highlight) HighLightForward();
580 }
581
LockSelObj()582 void LockSelObj()
583 {
584 register struct SelRec *sel_ptr;
585 register struct ObjRec *obj_ptr;
586 int changed=FALSE;
587
588 if (topSel==NULL) {
589 Msg(TgLoadString(STID_NO_OBJ_TO_LOCK));
590 return;
591 }
592 if (curChoice==VERTEXMODE) {
593 Msg(TgLoadString(STID_CANNOT_LOCK_IN_VERTEX_MODE));
594 return;
595 }
596 HighLightReverse();
597 StartCompositeCmd();
598 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
599 obj_ptr = sel_ptr->obj;
600 if (!obj_ptr->locked) {
601 changed = TRUE;
602 PrepareToReplaceAnObj(obj_ptr);
603 obj_ptr->locked = TRUE;
604 RecordReplaceAnObj(obj_ptr);
605 }
606 }
607 EndCompositeCmd();
608 HighLightForward();
609 if (changed) {
610 UpdSelBBox();
611 SetFileModified(TRUE);
612 justDupped = FALSE;
613 Msg(TgLoadString(STID_SEL_OBJ_ARE_LOCKED));
614 }
615 }
616
UnlockSelObj()617 void UnlockSelObj()
618 {
619 register struct SelRec *sel_ptr;
620 register struct ObjRec *obj_ptr;
621 int changed=FALSE;
622
623 if (topSel==NULL) {
624 Msg(TgLoadString(STID_NO_OBJ_TO_UNLOCK));
625 return;
626 }
627 if (curChoice==VERTEXMODE) {
628 Msg(TgLoadString(STID_CANNOT_UNLOCK_IN_VERTEX_MODE));
629 return;
630 }
631 HighLightReverse();
632 StartCompositeCmd();
633 for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
634 obj_ptr = sel_ptr->obj;
635 if (obj_ptr->locked) {
636 changed = TRUE;
637 PrepareToReplaceAnObj(obj_ptr);
638 obj_ptr->locked = FALSE;
639 RecordReplaceAnObj(obj_ptr);
640 }
641 }
642 EndCompositeCmd();
643 HighLightForward();
644 if (changed) {
645 UpdSelBBox();
646 SetFileModified(TRUE);
647 justDupped = FALSE;
648 Msg(TgLoadString(STID_SEL_OBJ_ARE_UNLOCKED));
649 }
650 }
651