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/pin.c,v 1.6 2011/05/16 16:21:58 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_PIN_C_
22 
23 #include "tgifdefs.h"
24 
25 #include "auxtext.e"
26 #include "choice.e"
27 #include "color.e"
28 #include "dialog.e"
29 #include "drawing.e"
30 #include "mainloop.e"
31 #include "msg.e"
32 #include "navigate.e"
33 #include "obj.e"
34 #include "pin.e"
35 #include "poly.e"
36 #include "raster.e"
37 #include "rect.e"
38 #include "select.e"
39 #include "setup.e"
40 #include "strtbl.e"
41 
42 int drawPolyToConnectPins=0;
43 
44 struct ObjRec *gpStartPin=NULL, *gpEndPin=NULL;
45 
46 static struct SelRec *topPinSel=NULL, *botPinSel=NULL;
47 
48 static struct ObjRec *gpHighLightedPin=NULL;
49 
50 static
CleanUpPinInfo()51 void CleanUpPinInfo()
52 {
53    struct SelRec *next_sel=NULL;
54 
55    for ( ; topPinSel != NULL; topPinSel=next_sel) {
56       next_sel = topPinSel->next;
57       free(topPinSel);
58    }
59    topPinSel = botPinSel = NULL;
60    gpStartPin = gpEndPin = NULL;
61 }
62 
63 static
CachePin(ObjPtr)64 void CachePin(ObjPtr)
65    struct ObjRec *ObjPtr;
66 {
67    struct SelRec *sel_ptr=(struct SelRec *)malloc(sizeof(struct SelRec));
68 
69    if (sel_ptr == NULL) FailAllocMessage();
70    memset(sel_ptr, 0, sizeof(struct SelRec));
71    sel_ptr->obj = ObjPtr;
72    sel_ptr->next = topPinSel;
73    sel_ptr->prev = NULL;
74    if (topPinSel == NULL) {
75       botPinSel = sel_ptr;
76    } else {
77       topPinSel->prev = sel_ptr;
78    }
79    topPinSel = sel_ptr;
80 }
81 
82 static
PreparePinInfoForAnObject(ObjPtr,nInsideAnIcon)83 void PreparePinInfoForAnObject(ObjPtr, nInsideAnIcon)
84    struct ObjRec *ObjPtr;
85    int nInsideAnIcon;
86 {
87    struct ObjRec *obj_ptr=NULL;
88 
89    switch (ObjPtr->type) {
90    case OBJ_GROUP:
91    case OBJ_SYM:
92       for (obj_ptr=ObjPtr->detail.r->last; obj_ptr != NULL;
93             obj_ptr=obj_ptr->prev) {
94          if (colorLayers && !ObjInVisibleLayer(obj_ptr)) {
95             continue;
96          }
97          PreparePinInfoForAnObject(obj_ptr, nInsideAnIcon);
98       }
99       break;
100    case OBJ_ICON:
101       if (nInsideAnIcon) return;
102       for (obj_ptr=ObjPtr->detail.r->last; obj_ptr != NULL;
103             obj_ptr=obj_ptr->prev) {
104          if (colorLayers && !ObjInVisibleLayer(obj_ptr)) {
105             continue;
106          }
107          PreparePinInfoForAnObject(obj_ptr, TRUE);
108       }
109       break;
110    case OBJ_PIN:
111       CachePin(ObjPtr);
112       break;
113    default: return;
114    }
115 }
116 
117 static
PreparePinInfo()118 void PreparePinInfo()
119 {
120    struct ObjRec *obj_ptr=NULL;
121 
122    gpStartPin = gpEndPin = NULL;
123    for (obj_ptr=botObj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
124       obj_ptr->tmp_child = NULL;
125       obj_ptr->tmp_parent = NULL;
126       if (colorLayers && !ObjInVisibleLayer(obj_ptr)) {
127          continue;
128       }
129       PreparePinInfoForAnObject(obj_ptr, FALSE);
130    }
131 }
132 
133 static
GetPins(pObj,ppTopSel,ppBotSel)134 int GetPins(pObj, ppTopSel, ppBotSel)
135    struct ObjRec *pObj;
136    struct SelRec **ppTopSel, **ppBotSel;
137 {
138    switch (pObj->type) {
139    case OBJ_GROUP: break;
140    case OBJ_SYM: break;
141    case OBJ_ICON: break;
142    case OBJ_PIN: break;
143    default: return FALSE;
144    }
145    topPinSel = botPinSel = NULL;
146    if (pObj->type == OBJ_PIN) {
147       PreparePinInfoForAnObject(pObj, FALSE);
148    } else {
149       struct ObjRec *pSubObj=NULL;
150       int nInsideAnIcon=(pObj->type==OBJ_ICON);
151 
152       for (pSubObj=pObj->detail.r->first; pSubObj != NULL;
153             pSubObj=pSubObj->next) {
154          PreparePinInfoForAnObject(pSubObj, nInsideAnIcon);
155       }
156    }
157    if (topPinSel == NULL) return FALSE;
158 
159    if (ppTopSel != NULL) *ppTopSel = topPinSel;
160    if (ppBotSel != NULL) *ppBotSel = botPinSel;
161    topPinSel = botPinSel = NULL;
162    return TRUE;
163 }
164 
165 static
AddObjToSorted(pObj,ppTopSel,ppBotSel)166 int AddObjToSorted(pObj, ppTopSel, ppBotSel)
167    struct ObjRec *pObj;
168    struct SelRec **ppTopSel, **ppBotSel;
169 {
170    int nIndex=(int)(long)(pObj->userdata);
171    struct SelRec *pSel=NULL;
172 
173    for (pSel=(*ppTopSel); pSel != NULL; pSel=pSel->next) {
174       if (nIndex > (int)(long)(pSel->obj->userdata)) {
175          return (AddObjIntoSel(pObj, pSel->prev, pSel, ppTopSel, ppBotSel) !=
176                NULL);
177       }
178    }
179    return (AddObjIntoSel(pObj, (*ppBotSel), NULL, ppTopSel, ppBotSel) != NULL);
180 }
181 
FindExtraPoly(pTopSel,pBotSel,ppTopSel,ppBotSel,pnCount,pBBox)182 int FindExtraPoly(pTopSel, pBotSel, ppTopSel, ppBotSel, pnCount, pBBox)
183    struct SelRec *pTopSel, *pBotSel;
184    struct SelRec **ppTopSel, **ppBotSel;
185    int *pnCount;
186    struct BBRec *pBBox;
187 {
188    struct SelRec *pSel=NULL, *first_poly_sel=NULL, *last_poly_sel=NULL;
189 
190    pBBox->ltx = pTopSel->obj->bbox.ltx;
191    pBBox->lty = pTopSel->obj->bbox.lty;
192    pBBox->rbx = pTopSel->obj->bbox.rbx;
193    pBBox->rby = pTopSel->obj->bbox.rby;
194    if (pnCount != NULL) (*pnCount) = 0;
195    for (pSel=pTopSel; pSel != NULL; pSel=pSel->next) {
196       struct SelRec *top_pin_sel=NULL, *bot_pin_sel=NULL;
197 
198       if (GetPins(pSel->obj, &top_pin_sel, &bot_pin_sel)) {
199          struct SelRec *pin_sel_ptr=NULL;
200 
201          for (pin_sel_ptr=top_pin_sel; pin_sel_ptr != NULL;
202                pin_sel_ptr=pin_sel_ptr->next) {
203             struct ConnRec *conn_ptr=NULL;
204 
205             for (conn_ptr=pin_sel_ptr->obj->detail.r->first_conn;
206                   conn_ptr != NULL; conn_ptr=conn_ptr->next) {
207                if (FindObjInSel(conn_ptr->poly_obj,
208                      first_poly_sel, last_poly_sel) == NULL) {
209                   PrependObjToSel(conn_ptr->poly_obj, &first_poly_sel,
210                         &last_poly_sel);
211                }
212             }
213          }
214          JustFreeSel(top_pin_sel, bot_pin_sel);
215       }
216    }
217    if (first_poly_sel == NULL) {
218       return FALSE;
219    } else {
220       struct SelRec *pPolySel=NULL, *pNextPolySel=NULL;
221       struct SelRec *pTopSortedSel=NULL, *pBotSortedSel=NULL;
222 
223       for (pPolySel=first_poly_sel; pPolySel != NULL; pPolySel=pNextPolySel) {
224          struct ObjRec *pPolyObj=pPolySel->obj;
225 
226          pNextPolySel = pPolySel->next;
227          for (pSel=pTopSel; pSel != NULL; pSel=pSel->next) {
228             if (pSel->obj == pPolyObj) {
229                UnlinkSel(pPolySel, &first_poly_sel, &last_poly_sel);
230                free(pPolySel);
231                break;
232             }
233          }
234          if (pSel == NULL) {
235             struct ObjRec *pObj=NULL;
236             int nIndex=0;
237 
238             for (pObj=topObj; pObj != NULL; pObj=pObj->next, nIndex++) {
239                if (pObj == pPolyObj) {
240                   pPolyObj->userdata = (void*)(long)nIndex;
241                   if (AddObjToSorted(pPolyObj,
242                         &pTopSortedSel, &pBotSortedSel)) {
243                   }
244                   if (pnCount != NULL) (*pnCount)++;
245                   ExpandBBox(&pPolyObj->bbox, pBBox);
246                   break;
247                }
248             }
249          }
250       }
251       JustFreeSel(first_poly_sel, last_poly_sel);
252       first_poly_sel = pTopSortedSel;
253       last_poly_sel = pBotSortedSel;
254    }
255    if (first_poly_sel == NULL) return FALSE;
256 
257    if (ppTopSel != NULL) *ppTopSel = first_poly_sel;
258    if (ppBotSel != NULL) *ppBotSel = last_poly_sel;
259    return TRUE;
260 }
261 
262 static
FindPinObj(AbsX,AbsY)263 struct ObjRec *FindPinObj(AbsX, AbsY)
264    int AbsX, AbsY;
265 {
266    struct SelRec *sel_ptr=NULL;
267 
268    for (sel_ptr=topPinSel; sel_ptr != NULL; sel_ptr=sel_ptr->next) {
269       if (PointInBBox(AbsX, AbsY, sel_ptr->obj->obbox)) {
270          return sel_ptr->obj;
271       }
272    }
273    return NULL;
274 }
275 
HighLightAPin(forward)276 void HighLightAPin(forward)
277    int forward;
278 {
279    if (drawPolyHighlightedNode != NULL) {
280       SelBox(drawWindow, revGrayGC,
281             OFFSET_X(drawPolyHighlightedNode->obbox.ltx)-2,
282             OFFSET_Y(drawPolyHighlightedNode->obbox.lty)-2,
283             OFFSET_X(drawPolyHighlightedNode->obbox.rbx)+2,
284             OFFSET_Y(drawPolyHighlightedNode->obbox.rby)+2);
285       if (forward) {
286          gpHighLightedPin = drawPolyHighlightedNode;
287       } else {
288          gpHighLightedPin = NULL;
289       }
290    }
291 }
292 
HandlePinHighlights(MouseX,MouseY)293 void HandlePinHighlights(MouseX, MouseY)
294    int MouseX, MouseY;
295 {
296    int need_to_highlight=FALSE, something_changed=FALSE;
297    struct ObjRec *obj_under_cursor=NULL;
298 
299    obj_under_cursor = FindPinObj(ABS_X(MouseX), ABS_Y(MouseY));
300    if (drawPolyHighlightedNode != NULL) {
301       if (obj_under_cursor != drawPolyHighlightedNode) {
302          /* un-highlight */
303          HighLightAPin(FALSE);
304          if (obj_under_cursor != NULL) {
305             drawPolyHighlightedNode = obj_under_cursor;
306             /* may need to call something like SetWiringNodeInfo()!? */
307          } else {
308             drawPolyHighlightedNode = NULL;
309             /* may need to call something like SetWiringNodeInfo()!? */
310          }
311          if (drawPolyHighlightedNode != NULL) {
312             need_to_highlight = TRUE;
313          }
314          something_changed = TRUE;
315       }
316    } else {
317       if (obj_under_cursor != NULL) {
318          drawPolyHighlightedNode = obj_under_cursor;
319          /* may need to call something like SetWiringNodeInfo()!? */
320          need_to_highlight = TRUE;
321          something_changed = TRUE;
322       }
323    }
324    if (need_to_highlight) {
325       HighLightAPin(TRUE);
326    }
327 }
328 
329 static
AppendConnToPin(pPinObj,pConn,pPolyObj)330 void AppendConnToPin(pPinObj, pConn, pPolyObj)
331    struct ObjRec *pPinObj, *pPolyObj;
332    struct ConnRec *pConn;
333 {
334    pPinObj->detail.r->pin_connected++;
335 
336    pConn->pin_obj = pPinObj;
337    pConn->poly_obj = pPolyObj;
338 
339    pConn->prev = pPinObj->detail.r->last_conn;
340    pConn->next = NULL;
341    if (pPinObj->detail.r->last_conn == NULL) {
342       pPinObj->detail.r->first_conn = pConn;
343    } else {
344       pPinObj->detail.r->last_conn->next = pConn;
345    }
346    pPinObj->detail.r->last_conn = pConn;
347 }
348 
349 static
CreateConnection(pStartPin,pEndPin)350 void CreateConnection(pStartPin, pEndPin)
351    struct ObjRec *pStartPin, *pEndPin;
352 {
353    struct ConnRec *pStartConn=NULL, *pEndConn=NULL;
354 
355    pStartConn = (struct ConnRec *)malloc(sizeof(struct ConnRec));
356    pEndConn = (struct ConnRec *)malloc(sizeof(struct ConnRec));
357    if (pStartConn == NULL || pEndConn == NULL) {
358       FailAllocMessage();
359       if (pStartConn != NULL) free(pStartConn);
360       if (pEndConn != NULL) free(pEndConn);
361       return;
362    }
363    memset(pStartConn, 0, sizeof(struct ConnRec));
364    memset(pEndConn, 0, sizeof(struct ConnRec));
365 
366    topObj->detail.p->start_conn = pStartConn;
367    topObj->detail.p->end_conn = pEndConn;
368 
369    pStartConn->at_start = TRUE;
370    pEndConn->at_start = FALSE;
371 
372    AppendConnToPin(pStartPin, pStartConn, topObj);
373    AppendConnToPin(pEndPin, pEndConn, topObj);
374 }
375 
ConnectPins()376 void ConnectPins()
377 {
378    int already_in_hyperspace=inHyperSpace, connecting=TRUE;
379    XGCValues values;
380 
381    PreparePinInfo();
382    if (topPinSel == NULL) {
383       MsgBox(TgLoadString(STID_NO_PINS_FOUND_IN_CUR_DRAWING), TOOL_NAME,
384             INFO_MB);
385       return;
386    }
387    MakeQuiescent();
388 
389    ResetWiringNodeInfo();
390    values.line_width = 3;
391    XChangeGC(mainDisplay, revGrayGC, GCLineWidth, &values);
392 
393    SetCurChoice(DRAWPOLY);
394    gstWiringInfo.num_ports_to_connect = 0;
395 
396    while (connecting) {
397       drawPolyToConnectPins = 2;
398       drawPolyHighlightedNode = gpHighLightedPin = NULL;
399       gpStartPin = gpEndPin = NULL;
400       SetStringStatus(TgLoadCachedString(CSTID_SEL_A_PIN_ESC_TO_END_DOTS));
401       for (;;) {
402          XEvent input;
403 
404          XNextEvent(mainDisplay, &input);
405          if (input.type == Expose) {
406             ExposeEventHandler(&input, TRUE);
407          } else if (input.type == KeyPress) {
408             if (KeyPressEventIsEscape(&input.xkey)) {
409                connecting = FALSE;
410                break;
411             }
412          } else if (input.xany.window == drawWindow) {
413             polyDrawn = FALSE;
414             DrawingEventHandler(&input);
415             if (curChoice == DRAWPOLY) {
416                if (polyDrawn) {
417                   break;
418                } else if (drawPolyToConnectPins == (-1)) {
419                   break;
420                }
421             } else {
422                polyDrawn = FALSE;
423                break;
424             }
425          }
426       }
427       drawPolyToConnectPins = 0;
428       if (gpHighLightedPin != NULL) {
429          drawPolyHighlightedNode = gpHighLightedPin;
430          /* may need to call something like SetWiringNodeInfo()!? */
431          HighLightAPin(FALSE);
432       }
433       drawPolyHighlightedNode = gpHighLightedPin = NULL;
434 
435       if (gpStartPin != NULL && gpEndPin != NULL) {
436          CreateConnection(gpStartPin, gpEndPin);
437       }
438    }
439    SetCurChoice(NOTHING);
440 
441    values.line_width = 1;
442    XChangeGC(mainDisplay, revGrayGC, GCLineWidth, &values);
443    if (already_in_hyperspace && !inHyperSpace) ToggleHyperSpace(TRUE);
444 
445    CleanUpPinInfo();
446 }
447 
FreeConn(pConn)448 void FreeConn(pConn)
449    struct ConnRec *pConn;
450 {
451    free(pConn);
452 }
453 
454 static
UnlinkConn(pConn)455 void UnlinkConn(pConn)
456    struct ConnRec *pConn;
457 {
458    struct GroupRec *pGroup=pConn->pin_obj->detail.r;
459 
460    if (pGroup->first_conn == pConn) {
461       pGroup->first_conn = pConn->next;
462    } else {
463       pConn->prev->next = pConn->next;
464    }
465    if (pGroup->last_conn == pConn) {
466       pGroup->last_conn = pConn->prev;
467    } else {
468       pConn->next->prev = pConn->prev;
469    }
470    pGroup->pin_connected--;
471    pConn->pin_obj = NULL;
472 }
473 
DelConnFromPoly(pConn)474 void DelConnFromPoly(pConn)
475    struct ConnRec *pConn;
476 {
477    pConn->poly_obj = NULL;
478    UnlinkConn(pConn);
479    FreeConn(pConn);
480 }
481 
DelConnFromPin(pConn)482 void DelConnFromPin(pConn)
483    struct ConnRec *pConn;
484 {
485    /* struct ObjRec *pPinObj=pConn->pin_obj; */
486    struct ObjRec *pPolyObj=pConn->poly_obj;
487 
488    if (pConn->at_start) {
489       pPolyObj->detail.p->start_conn = NULL;
490    } else {
491       pPolyObj->detail.p->end_conn = NULL;
492    }
493    UnlinkConn(pConn);
494    FreeConn(pConn);
495 
496    DelObj(pPolyObj);
497 }
498 
CleanUpPins()499 void CleanUpPins()
500 {
501 }
502 
InitPins()503 int InitPins()
504 {
505    return TRUE;
506 }
507 
508