2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
6 // $Header: r:/t2repos/thief2/src/editor/editlink.cpp,v 1.14 1998/02/04 13:53:26 dc Exp $
31 // for the windows controls
32 #define WIN32_LEAN_AND_MEAN
43 // must be last header
52 LinkEditorDesc editdesc
;
64 #define ID_LINKED "LinkEditor: ed"
67 #define ID_ADDBUTTON 0
68 #define ID_DELETEBUTTON 1
69 #define ID_DONEBUTTON 2
72 // END for the windows controls
76 // add a single line (LinkID, source objid, dest objid, flavor) to the list view
78 static LinkID
get_item_linkid(LinkEditor
* ed
, int idx
)
83 item
.mask
= LVIF_PARAM
;
84 if (ListView_GetItem(ed
->hWndList
,&item
))
85 return (LinkID
)item
.lParam
;
90 extern BOOL show_internal_links
= FALSE
;
92 BOOL
LinkEditorShowAllLinks(BOOL newval
)
94 BOOL old
= show_internal_links
;
95 show_internal_links
= newval
;
99 BOOL
linkedit_fill_line(HWND hWnd
, int index
, LinkID id
, sLinkAndData
* link
)
101 char buf
[MAX_STRLEN
];
102 AutoAppIPtr_(LinkManager
,LinkMan
);
103 IRelation
* rel
= LinkMan
->GetRelation(link
->flavor
);
104 const char* flavor
= rel
->Describe()->name
;
106 ListView_SetItemText(hWnd
, index
, 0, (char*)flavor
);
107 sprintf(buf
, "%08X", id
);
108 ListView_SetItemText(hWnd
, index
, 1, buf
);
110 ListView_SetItemText(hWnd
, index
, 2, (char*)ObjEditName(link
->source
));
111 ListView_SetItemText(hWnd
, index
, 3, (char*)ObjEditName(link
->dest
));
112 if (link
->data
!= NULL
)
114 AutoAppIPtr_(StructDescTools
,pTools
);
115 const sRelationDataDesc
* ddesc
= rel
->DescribeData();
116 const sStructDesc
* sdesc
= pTools
->Lookup(ddesc
->type
);
118 sprintf(buf
,"%08X",link
->data
);
121 pTools
->UnparseSimple(sdesc
,link
->data
,buf
,sizeof(buf
));
123 ListView_SetItemText(hWnd
, index
, 4, buf
);
133 void LGAPI
edit_cb(sStructEditEvent
* , StructEditCBData data
);
135 static void linkedit_edit_data(LinkEditor
* ed
, int idx
)
137 LinkID id
= get_item_linkid(ed
,idx
);
138 if (id
== LINKID_NULL
) return;
140 AutoAppIPtr_(LinkManager
,LinkMan
);
141 void* data
= LinkMan
->GetData(id
);
145 IRelation
* Rel
= LinkMan
->GetRelation(LINKID_RELATION(id
));
146 const sRelationDataDesc
* ddesc
= Rel
->DescribeData();
148 if (ddesc
->size
<= 0)
153 char* blank
= new char[ddesc
->size
];
154 memset(blank
,0,ddesc
->size
);
155 Rel
->SetData(id
,blank
);
156 data
= Rel
->GetData(id
);
160 AutoAppIPtr_(StructDescTools
,pTools
);
162 const sStructDesc
* sdesc
= pTools
->Lookup(ddesc
->type
);
165 sStructEditorDesc editdesc
= { "", kStructEditAllButtons
};
166 strcpy(editdesc
.title
,ddesc
->type
);
167 IStructEditor
* sed
= CreateStructEditor(&editdesc
,(sStructDesc
*)sdesc
,data
);
168 sed
->SetCallback(edit_cb
,(StructEditCBData
)ed
);
169 sed
->Go(kStructEdModeless
);
176 int linkedit_add_line(HWND hWnd
, int index
, LinkID id
, sLinkAndData
* link
)
181 item
.mask
= LVIF_TEXT
| LVIF_STATE
| LVIF_PARAM
;
187 item
.cchTextMax
= MAX_STRLEN
;
189 ListView_InsertItem(hWnd
, &item
);
190 linkedit_fill_line(hWnd
,index
,id
,link
);
196 // start at item #start (0 means start at beginning of list)
197 int linkedit_find_selected(HWND hWnd
, int start
)
199 if (ListView_GetSelectedCount(hWnd
))
200 for (int i
=start
; i
<ListView_GetItemCount(hWnd
); i
++)
201 if (ListView_GetItemState(hWnd
, i
, LVIS_SELECTED
))
207 // this is to be filled in by the AddLinkDlgProc
208 // this is static because there can be only one link add dialog at a time, and we
209 // can't attach a LinkEditor* to the dialog
210 static sLinkAndData dlg_add_link
;
212 #pragma off(unreferenced)
213 // add link dialog DlgProc
214 BOOL CALLBACK
AddLinkDlgProc(HWND hDlg
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
219 ILinkManager
* pLinkMan
;
220 const sRelationDesc
* reldesc
;
225 pLinkMan
= AppGetObj(ILinkManager
);
227 // go through the list of all flavors and add them to the dropdown box
228 pLinkMan
->IterStart(&iter
);
229 while (pLinkMan
->IterNext(&iter
, &flavor
))
231 IRelation
* pRel
= pLinkMan
->GetRelation(flavor
);
233 reldesc
= pRel
->Describe();
234 if (show_internal_links
|| !(reldesc
->flags
& kRelationNoEdit
))
236 int idx
= SendDlgItemMessage(hDlg
, IDC_FLAVORCOMBO
, CB_ADDSTRING
, 0, (LPARAM
)(LPCTSTR
)reldesc
->name
);
237 SendDlgItemMessage(hDlg
, IDC_FLAVORCOMBO
, CB_SETITEMDATA
, (WPARAM
)idx
, (LPARAM
)pRel
->GetID());
242 pLinkMan
->IterStop(&iter
);
243 SafeRelease(pLinkMan
);
247 switch (LOWORD(wParam
))
251 // add the new link from the dialog
254 GetDlgItemText(hDlg
, IDC_FROMEDIT
, buf
, 15);
255 dlg_add_link
.source
= EditGetObjNamed(buf
);
257 GetDlgItemText(hDlg
, IDC_TOEDIT
, buf
, 15);
258 dlg_add_link
.dest
= EditGetObjNamed(buf
);
260 dlg_add_link
.data
= NULL
;
261 int idx
= SendDlgItemMessage(hDlg
, IDC_FLAVORCOMBO
, CB_GETCURSEL
, 0, 0);
262 int id
= SendDlgItemMessage(hDlg
, IDC_FLAVORCOMBO
, CB_GETITEMDATA
, (WPARAM
)idx
, 0);
264 dlg_add_link
.flavor
= (RelationID
)id
;
265 EndDialog(hDlg
, TRUE
);
270 EndDialog(hDlg
, FALSE
);
274 MessageBox(hDlg
, "edit data here", "Info", MB_OK
| MB_ICONINFORMATION
);
282 #pragma on(unreferenced)
284 // puts up the dialog to add a link and does it
285 void linkedit_add_link(LinkEditor
* ed
, HWND hWnd
)
287 sLinkAndData
& link
= dlg_add_link
;
289 memset(&link
, 0, sizeof(sLinkAndData
));
291 if (DialogBox(ed
->hInst
, "AddLink", hWnd
, AddLinkDlgProc
))
293 AutoAppIPtr_(LinkManager
,pLinkMan
);
294 const sRelationDesc
* reldesc
= NULL
;
296 if (link
.flavor
== 0)
298 MessageBeep(MB_ICONEXCLAMATION
);
299 MessageBox(hWnd
, "Flavor is invalid!", "Add Link Error", MB_OK
| MB_ICONEXCLAMATION
);
303 // get the text description of the flavor
304 pLinkMan
= AppGetObj(ILinkManager
);
305 cAutoIPtr
<IRelation
> pRel (pLinkMan
->GetRelation(link
.flavor
));
307 reldesc
= pRel
->Describe();
309 // can't link myself to myself
310 if (link
.source
== link
.dest
)
312 MessageBeep(MB_ICONEXCLAMATION
);
313 MessageBox(hWnd
, "Source and dest ObjID's can't be the same", "Add Link Error", MB_OK
| MB_ICONEXCLAMATION
);
316 // check for valid objids
317 if (!ObjectExists(link
.source
))
321 sprintf(str
, "Source ObjID %d is invalid!\n", link
.source
);
322 MessageBeep(MB_ICONEXCLAMATION
);
323 MessageBox(hWnd
, str
, "Add Link Error", MB_OK
| MB_ICONEXCLAMATION
);
326 if (!ObjectExists(link
.dest
))
330 sprintf(str
, "Dest ObjID %d is invalid!\n", link
.dest
);
331 MessageBeep(MB_ICONEXCLAMATION
);
332 MessageBox(hWnd
, str
, "Add Link Error", MB_OK
| MB_ICONEXCLAMATION
);
336 LinkID id
= pLinkMan
->Add(link
.source
,link
.dest
,link
.flavor
);
337 link
.data
= pLinkMan
->GetData(id
);
338 int idx
= linkedit_add_line(hWnd
, ListView_GetItemCount(hWnd
), id
, &link
);
339 if (link
.data
!= NULL
)
340 linkedit_edit_data(ed
,idx
);
344 // called when the delete button is pressed and a link is selected
345 void linkedit_delete_link(LinkEditor
* ed
, HWND hWnd
, int index
)
347 LinkID id
= get_item_linkid(ed
,index
);
348 if (id
== LINKID_NULL
) return;
349 AutoAppIPtr_(LinkManager
,LinkMan
);
351 ListView_DeleteItem(hWnd
, index
);
354 // finds all selected links and deletes them all
355 void linkedit_delete_selected(LinkEditor
* ed
, HWND hWnd
)
357 int num
= linkedit_find_selected(hWnd
, -1);
360 MessageBeep(MB_ICONHAND
);
361 int result
= MessageBox(hWnd
, "Are you sure?", "Delete Link", MB_YESNO
| MB_ICONWARNING
| MB_DEFBUTTON2
);
366 linkedit_delete_link(ed
, hWnd
, num
);
368 while ((num
= linkedit_find_selected(hWnd
, num
)) != -1);
373 // add all links for one objid to the list box
374 void linkedit_add_all_items(HWND hWnd
, ObjID objid_src
, ObjID objid_dest
, RelationID relid
)
376 ILinkManager
* pLinkMan
= AppGetObj(ILinkManager
);
380 // add the items which match the given query
381 pQuery
= pLinkMan
->Query(objid_src
, objid_dest
, relid
);
382 for (; !pQuery
->Done(); pQuery
->Next())
385 memset(&link
,0,sizeof(link
));
387 LinkID id
= pQuery
->ID();
388 IRelation
* rel
= pLinkMan
->GetRelation(LINKID_RELATION(id
));
389 const sRelationDesc
* desc
= rel
->Describe();
390 if (!show_internal_links
&& (desc
->flags
& kRelationNoEdit
))
397 link
.data
= pQuery
->Data();
398 linkedit_add_line(hWnd
, index
++, id
, &link
);
401 SafeRelease(pLinkMan
);
404 // WndProc for the link editor
405 LRESULT CALLBACK
LinkEditorWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
410 // get my parent so I can get the LinkEditor* from it
411 parent
= GetParent(hWnd
);
414 ed
= (LinkEditor
*) GetProp(parent
, ID_LINKED
);
419 switch(LOWORD(wParam
))
422 linkedit_add_link(ed
, ed
->hWndList
);
425 case ID_DELETEBUTTON
:
426 linkedit_delete_selected(ed
, ed
->hWndList
);
430 DestroyWindow(ed
->hWnd
);
434 // keep the list view active so we can see what's highlighted
435 SetFocus(ed
->hWndList
);
440 hdr
= (NMHDR
*)lParam
;
441 if (hdr
->code
== NM_DBLCLK
)
443 int idx
= linkedit_find_selected(ed
->hWndList
, 0);
446 linkedit_edit_data(ed
,idx
);
452 LinkEditorDestroy(ed
);
456 return DefWindowProc(hWnd
, msg
, wParam
, lParam
);
459 static const char* relid_name(RelationID id
)
461 if (id
== RELID_NULL
) return "any";
463 ILinkManager
* linkman
= AppGetObj(ILinkManager
);
464 IRelation
* rel
= linkman
->GetRelation(id
);
465 const char* out
= rel
->Describe()->name
;
466 SafeRelease(linkman
);
471 #define objid_name(obj) ((obj == LINKOBJ_WILDCARD) ? "any" : ObjEditName(obj))
473 static const char* default_title(ObjID src
, ObjID dst
, RelationID relid
)
477 sprintf(buf
,"Links: %s --[%s]--> %s",objid_name(src
),relid_name(relid
),objid_name(dst
));
482 // create me a link editor for an objid
483 LinkEditor
* LinkEditorCreate(ObjID objid_src
, ObjID objid_dest
, RelationID relid
, LinkEditorDesc
* editdesc
)
486 const char* szName
= "Link Editor";
492 int width
, height
, left
, top
;
494 ed
= (LinkEditor
*)Malloc(sizeof(LinkEditor
));
496 // we need the main app's HWND
497 pWA
= AppGetObj(IWinApp
);
498 hMainWnd
= pWA
->GetMainWnd();
501 // we also need the main app's HINSTANCE
502 hMainInst
= (HINSTANCE
) GetWindowLong(hMainWnd
, GWL_HINSTANCE
);
504 // set up the new window's class
505 memset(&wc
, 0, sizeof(WNDCLASS
));
506 wc
.style
= CS_HREDRAW
| CS_VREDRAW
;
507 wc
.lpfnWndProc
= LinkEditorWndProc
;
508 wc
.hInstance
= hMainInst
;
509 wc
.hbrBackground
= (HBRUSH
) GetStockObject(LTGRAY_BRUSH
);
510 wc
.lpszClassName
= szName
;
518 left
= (GetSystemMetrics(SM_CXSCREEN
) - width
) / 2;
519 top
= (GetSystemMetrics(SM_CYSCREEN
) - height
) / 2;
522 const char* title
= editdesc
->title
;
524 title
= default_title(objid_src
,objid_dest
,relid
);
527 ed
->hWnd
= CreateWindow(szName
, (char*)title
, WS_OVERLAPPED
, left
, top
, width
, height
,
528 hMainWnd
, NULL
, hMainInst
, NULL
);
530 ShowWindow(ed
->hWnd
, SW_SHOWNORMAL
);
531 UpdateWindow(ed
->hWnd
);
533 // Create a nice standard Windows font for the controls.
535 memset(&logFont
, 0, sizeof(LOGFONT
));
536 logFont
.lfCharSet
= DEFAULT_CHARSET
;
537 logFont
.lfHeight
= 12;
538 strcpy(logFont
.lfFaceName
, "MS Sans Serif");
539 ed
->hWndFont
= CreateFontIndirect(&logFont
);
541 // get our new window's HINSTANCE
542 ed
->hInst
= (HINSTANCE
) GetWindowLong(ed
->hWnd
, GWL_HINSTANCE
);
544 SetProp(ed
->hWnd
, ID_LINKED
, (HANDLE
)ed
);
545 ed
->hMainWnd
= hMainWnd
;
546 ed
->objid_src
= objid_src
;
547 ed
->objid_dest
= objid_dest
;
550 // create some buttons
552 btnWnd
= CreateWindow("BUTTON", "Add", WS_VISIBLE
| WS_CHILD
| BS_PUSHBUTTON
,
553 60, 340, 65, 25, ed
->hWnd
, (HMENU
) ID_ADDBUTTON
, ed
->hInst
, NULL
);
555 SendMessage(btnWnd
, WM_SETFONT
, (WPARAM
)ed
->hWndFont
, 0);
557 btnWnd
= CreateWindow("BUTTON", "Delete", WS_VISIBLE
| WS_CHILD
| BS_PUSHBUTTON
,
558 135, 340, 65, 25, ed
->hWnd
, (HMENU
) ID_DELETEBUTTON
, ed
->hInst
, NULL
);
560 SendMessage(btnWnd
, WM_SETFONT
, (WPARAM
)ed
->hWndFont
, 0);
562 btnWnd
= CreateWindow("BUTTON", "Done", WS_VISIBLE
| WS_CHILD
| BS_PUSHBUTTON
,
563 375, 340, 65, 25, ed
->hWnd
, (HMENU
) ID_DONEBUTTON
, ed
->hInst
, NULL
);
565 SendMessage(btnWnd
, WM_SETFONT
, (WPARAM
)ed
->hWndFont
, 0);
569 SendMessage(btnWnd
, WM_SETFONT
, (WPARAM
)ed
->hWndFont
, 0);
571 // make it fill most of the window
572 width
= 500 - GetSystemMetrics(SM_CXFIXEDFRAME
) * 2;
577 // now, let's create the list view
578 ed
->hWndList
= CreateWindowEx(0L, WC_LISTVIEW
, "", WS_VISIBLE
| WS_CHILD
| LVS_REPORT
, top
,
579 left
, width
, height
, ed
->hWnd
, (HMENU
) ID_LISTVIEW
, ed
->hInst
, NULL
);
581 // set up the columns
582 col
.mask
= LVCF_FMT
| LVCF_WIDTH
| LVCF_TEXT
;
583 col
.fmt
= LVCFMT_LEFT
;
585 col
.pszText
= "Flavor";
586 ListView_InsertColumn(ed
->hWndList
, 0, &col
);
589 ListView_InsertColumn(ed
->hWndList
, 1, &col
);
591 col
.pszText
= "From";
592 ListView_InsertColumn(ed
->hWndList
, 2, &col
);
594 ListView_InsertColumn(ed
->hWndList
, 3, &col
);
596 col
.fmt
= LVCFMT_RIGHT
;
597 col
.pszText
= "Data";
598 ListView_InsertColumn(ed
->hWndList
, 4, &col
);
600 // insert all of the items
601 linkedit_add_all_items(ed
->hWndList
, ed
->objid_src
, ed
->objid_dest
, ed
->relid
);
606 // destroy the link editor
607 void LinkEditorDestroy(LinkEditor
* ed
)
611 DeleteObject(ed
->hWndFont
);
614 SetFocus(ed
->hMainWnd
);
615 RemoveProp(ed
->hWnd
, ID_LINKED
);
619 static void refresh_all_fields(LinkEditor
* ed
)
621 AutoAppIPtr_(LinkManager
,LinkMan
);
622 int max
= ListView_GetItemCount(ed
->hWndList
);
623 for (int idx
= 0; idx
< max
; idx
++)
625 LinkID id
= get_item_linkid(ed
,idx
);
626 if (id
== LINKID_NULL
)
629 LinkMan
->Get(id
,&link
);
630 link
.data
= LinkMan
->GetData(id
);
631 linkedit_fill_line(ed
->hWndList
,idx
,id
,&link
);
635 static void LGAPI
edit_cb(sStructEditEvent
* , StructEditCBData data
)
637 LinkEditor
* ed
= (LinkEditor
*)data
;
638 refresh_all_fields(ed
);