2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
6 // $Header: r:/t2repos/thief2/src/editor/editplst.cpp,v 1.14 1998/03/14 21:07:57 mahk Exp $
8 // Property List Editor
30 // for the windows controls
31 #define WIN32_LEAN_AND_MEAN
41 // must be last header
45 #define ID_VIEWBUTTON 0
46 #define ID_DELETEBUTTON 1
47 #define ID_DONEBUTTON 2
51 #define NUM_BUTTONS EDPLIST_NUM_BUTTONS
53 #define ID_PLISTED "PropertyListEditor: ed"
54 // END for the windows controls
56 static const char* button_names
[] = { "Add", "Delete", "Done" };
60 #define BUTTON_W (65 +GetSystemMetrics(SM_CXBORDER)*2)
61 #define BUTTON_H (25 +GetSystemMetrics(SM_CYBORDER)*2)
73 #define BUTTONS_W (NUM_BUTTONS*BUTTON_W + (NUM_BUTTONS-1)*MARGIN_X)
75 #define WINDOW_W (2*MARGIN_X +BUTTONS_W)
76 #define WINDOW_H (MARGIN_Y+METABOX_H+MARGIN_Y+PROPBOX_H+MARGIN_Y+BUTTON_H+MARGIN_Y)
82 static int num_editors
= 0; // number of editors currently out there.
87 void BuildUI(PropertyListEditor
* ed
, PropertyListEditorDesc
* editdesc
);
88 void PropertyListEditorDestroy(PropertyListEditor
* ed
);
90 // these flags tell PropertyListEditorFillBox which properties to display
94 static char* view_button_text
[] = { "Cancel", "Add" };
97 //------------------------------------------------------------
101 void PropertyListEditorFillBox(PropertyListEditor
*ed
, int mode
);
102 void PropertyListEditorFillMetaBox(PropertyListEditor
*ed
, int mode
);
105 static void change_edit_mode(PropertyListEditor
* ed
, int mode
)
107 if (mode
== ed
->mode
)
111 SetWindowText(ed
->hWndButtons
[ID_VIEWBUTTON
],view_button_text
[mode
]);
112 EnableWindow(ed
->hWndButtons
[ID_DELETEBUTTON
], mode
== kRelevant
);
114 PropertyListEditorFillBox(ed
, mode
);
115 PropertyListEditorFillMetaBox(ed
, mode
);
119 //------------------------------------------------------------
120 // THE PROPERTY LIST BOX
124 // Return the string for an item, concats together string with value
127 static char* prop_item_string(ObjID obj
, IProperty
* prop
)
130 sprintf(buf
,"%s",prop
->Describe()->name
);
132 if (!prop
->IsSimplyRelevant(obj
))
135 AutoAppIPtr_(StructDescTools
,pTools
);
136 const sPropertyTypeDesc
* tdesc
= prop
->DescribeType();
137 const sStructDesc
* sdesc
= pTools
->Lookup(tdesc
->type
);
138 if (tdesc
->size
> 0 && sdesc
)
141 if (FAILED(COMQueryInterface(prop
,IID_IPropertyRaw
,(void**)&raw
)))
145 char* val
= new char[tdesc
->size
];
148 // add a colon and the value
150 pTools
->UnparseSimple(sdesc
,val
,buf
+strlen(buf
),sizeof(buf
)-strlen(buf
));
159 BOOL property_show_all
= FALSE
;
162 // puts all the wanted properties in a listbox
163 void PropertyListEditorFillBox(PropertyListEditor
*ed
, int mode
)
165 IPropertyManager
* propMan
= AppGetObj(IPropertyManager
);
169 // clear out the listbox
170 SendMessage(ed
->hWndPropBox
, LB_RESETCONTENT
, 0, 0);
172 // go through all properties and put them in the list box
173 propMan
->BeginIter(&iter
);
174 while ((prop
= propMan
->NextIter(&iter
)) != NULL
)
176 if (!property_show_all
&& (prop
->Describe()->flags
& kPropertyNoEdit
))
179 BOOL isIrrel
= mode
==kIrrelevant
;
180 if (isIrrel
== !prop
->IsSimplyRelevant(ed
->editID
))
182 SendMessage(ed
->hWndPropBox
, LB_ADDSTRING
, 0, (LPARAM
) prop_item_string(ed
->editID
,prop
));
186 SafeRelease(propMan
);
189 static void proplist_edit_cb(PropEditEvent
* , PropEditCBData data
)
191 PropertyListEditor
* ed
= (PropertyListEditor
*)data
;
192 PropertyListEditorFillBox(ed
,ed
->mode
);
197 static IProperty
* selected_property(PropertyListEditor
* ed
)
200 AutoAppIPtr_(PropertyManager
,propMan
);
202 int index
= SendMessage(ed
->hWndPropBox
, LB_GETCURSEL
, 0, 0);
204 return propMan
->GetProperty(PROPID_NULL
);
205 SendMessage(ed
->hWndPropBox
, LB_GETTEXT
, index
, (LPARAM
)buf
);
207 // strip off first token
208 char* space
= strchr(buf
,':');
209 if (space
== NULL
) space
= strchr(buf
,' ');
210 if (space
) *space
= '\0';
212 IProperty
* prop
= propMan
->GetPropertyNamed(buf
);
218 #pragma off(unreferenced)
219 static void handle_propbox_command(PropertyListEditor
* ed
, WPARAM wParam
, LPARAM lParam
)
221 switch (HIWORD(wParam
))
225 IProperty
* prop
= selected_property(ed
);
226 if (ed
->mode
== kIrrelevant
)
227 prop
->Create(ed
->editID
);
228 PropertyEditor
* ped
= PropertyEditorCreate(prop
, ed
->editID
);
231 // Unset the property, to make listeners & the cancel button happy
232 if (ed
->mode
== kIrrelevant
)
233 prop
->Delete(ed
->editID
);
235 PropertyEditorInstallCallback(ped
,proplist_edit_cb
,(PropEditCBData
)ed
);
237 // snap back to relevant mode
238 change_edit_mode(ed
,kRelevant
);
246 int index
= SendMessage(ed
->hWndPropBox
, LB_GETCURSEL
, 0, 0);
247 if (index
!= LB_ERR
) // selection is defined
249 // de-select the meta prop box
250 SendMessage(ed
->hWndMetaBox
, LB_SETCURSEL
, (WPARAM
)-1, 0);
256 #pragma on(unrefereced)
258 //------------------------------------------------------------
259 // THE METAPROPERTY LIST BOX
263 #define MAKE_META_DATA(pri,obj) (((pri)<< 16) | ((obj) & 0xFFFF))
264 #define META_DATA_OBJ(dat) (short)((dat) & 0xFFFF)
265 #define META_DATA_PRI(dat) (tDonorPriority)((dat) >> 16)
267 static void PropertyListEditorFillMetaBox(PropertyListEditor
* ed
, int mode
)
271 IObjectQuery
* donors
;
272 IDonorQuery
* dq
= NULL
;
273 AutoAppIPtr_(TraitManager
,traitman
);
274 AutoAppIPtr_(ObjectSystem
,objsys
);
276 // clear out the listbox
277 SendMessage(ed
->hWndMetaBox
, LB_RESETCONTENT
, 0, 0);
279 // metaproperties can't have metaproperties, sorry
280 if (mode
== kIrrelevant
&& traitman
->IsMetaProperty(ed
->editID
))
283 if (mode
== kRelevant
)
285 donors
= traitman
->Query(ed
->editID
,kTraitQueryDonors
);
286 COMQueryInterface(donors
,IID_IDonorQuery
,(void**)&dq
);
290 donors
= traitman
->Query(traitman
->RootMetaProperty(),kTraitQueryAllDescendents
);
293 for (; !donors
->Done(); donors
->Next())
295 ObjID obj
= donors
->Object();
296 if (mode
== kIrrelevant
&& !traitman
->IsMetaProperty(obj
))
299 const Label
* name
= objsys
->GetName(obj
);
301 int index
= SendMessage(ed
->hWndMetaBox
, LB_INSERTSTRING
, (WPARAM
)-1, (LPARAM
) name
->text
);
303 tDonorPriority pri
= (dq
) ? dq
->Priority() : 0;
304 SendMessage(ed
->hWndMetaBox
, LB_SETITEMDATA
, (WPARAM
)index
, (LPARAM
) MAKE_META_DATA(pri
,obj
));
311 static ObjID
selected_metaproperty(PropertyListEditor
* ed
)
315 int index
= SendMessage(ed
->hWndMetaBox
, LB_GETCURSEL
, 0, 0);
316 long data
= SendMessage(ed
->hWndMetaBox
, LB_GETITEMDATA
, index
, 0);
318 return META_DATA_OBJ(data
);
319 #ifdef PARSE_METAPROP
320 AutoAppIPtr(ObjectSystem
);
323 strncpy(label
.text
,buf
,sizeof(label
.text
));
324 label
.text
[sizeof(label
.text
)-1] = '\0';
327 return pObjectSystem
->GetObjectNamed(&label
);
334 BOOL
confirm(HWND hWnd
, const char* question
);
336 void remove_selected_metaproperty(PropertyListEditor
* ed
)
338 int index
= SendMessage(ed
->hWndMetaBox
, LB_GETCURSEL
, 0, 0);
341 long data
= SendMessage(ed
->hWndMetaBox
, LB_GETITEMDATA
, index
, 0);
343 if (confirm(ed
->hWnd
,"Delete metaproperty?"))
345 AutoAppIPtr_(TraitManager
,traitMan
);
346 traitMan
->RemoveObjMetaPropertyPrioritized(ed
->editID
,META_DATA_OBJ(data
),META_DATA_PRI(data
));
347 PropertyListEditorFillMetaBox(ed
, ed
->mode
);
351 #pragma off(unreferenced)
352 static void handle_metabox_command(PropertyListEditor
* ed
, WPARAM wParam
, LPARAM lParam
)
354 switch (HIWORD(wParam
))
359 ObjID mprop
= selected_metaproperty(ed
);
360 if (mprop
== OBJ_NULL
) break;
362 if (ed
->mode
== kRelevant
)
364 PropertyListEditorDesc edesc
= { "" };
365 PropertyListEditorCreate(mprop
, &edesc
);
369 AutoAppIPtr_(TraitManager
,traitman
);
370 traitman
->AddObjMetaProperty(ed
->editID
,mprop
);
371 // snap back to relevant mode
372 change_edit_mode(ed
,kRelevant
);
379 int index
= SendMessage(ed
->hWndMetaBox
, LB_GETCURSEL
, 0, 0);
380 if (index
!= LB_ERR
) // selection is defined
382 // de-select the prop box
383 SendMessage(ed
->hWndPropBox
, LB_SETCURSEL
, (WPARAM
)-1, 0);
389 #pragma on(unreferenced)
391 //------------------------------------------------------------
394 static BOOL
confirm(HWND hWnd
, const char* question
)
396 MessageBeep(MB_ICONHAND
);
397 int result
= MessageBox(hWnd
, question
, "Confirm:" , MB_YESNO
| MB_ICONWARNING
| MB_DEFBUTTON2
);
398 return result
== IDYES
;
402 //------------------------------------------------------------
403 // WndProc for PropertyListEditor
405 LRESULT CALLBACK
PropertyListEditorWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
408 PropertyListEditor
*ed
;
410 // get the PropertyListEditor* from the parent window
411 parent
= GetParent(hWnd
);
414 ed
= (PropertyListEditor
*) GetProp(parent
, ID_PLISTED
);
419 switch(LOWORD(wParam
))
422 // switch from add mode to view mode
423 change_edit_mode(ed
,!ed
->mode
);
427 case ID_DELETEBUTTON
:
429 IProperty
* prop
= selected_property(ed
);
431 // delete the currently selected property
432 if (prop
->GetID() != PROPID_NULL
)
434 if (confirm(hWnd
, "Remove property?"))
436 prop
->Delete(ed
->editID
);
437 PropertyListEditorFillBox(ed
, ed
->mode
);
442 remove_selected_metaproperty(ed
);
451 DestroyWindow(ed
->hWnd
);
455 handle_propbox_command(ed
,wParam
,lParam
);
459 handle_metabox_command(ed
,wParam
,lParam
);
466 PropertyListEditorDestroy(ed
);
470 return DefWindowProc(hWnd
, msg
, wParam
, lParam
);
473 //-----------------------------------------------------------------------------
474 // Present a view with a list of all the properties for an object. Each
475 // property can then be edited with the property editor.
476 //-----------------------------------------------------------------------------
477 PropertyListEditor
* PropertyListEditorCreate(ObjID editID
, PropertyListEditorDesc
* editdesc
)
479 PropertyListEditor
*ed
;
481 ed
= (PropertyListEditor
*)Malloc(sizeof(PropertyListEditor
));
482 memset(ed
, 0, sizeof(PropertyListEditor
));
485 ed
->mode
= kRelevant
;
488 BuildUI(ed
, editdesc
);
489 SetProp(ed
->hWnd
, ID_PLISTED
, (HANDLE
)ed
);
490 PropertyListEditorFillBox(ed
, ed
->mode
);
491 PropertyListEditorFillMetaBox(ed
, ed
->mode
);
497 // Create default title
500 static const char* default_title(ObjID obj
)
503 sprintf(buf
,"Properties for %s",ObjEditName(obj
));
507 //-----------------------------------------------------------------------------
508 // Create all the GUI elements needed to show the property list.
509 //-----------------------------------------------------------------------------
510 void BuildUI(PropertyListEditor
* ed
, PropertyListEditorDesc
* editdesc
)
515 const char* szName
= "Property List Editor";
516 int width
, height
, top
, left
;
518 // we need the main app's HWND
519 pWA
= AppGetObj(IWinApp
);
520 ed
->hMainWnd
= pWA
->GetMainWnd();
523 // we also need the main app's HINSTANCE
524 hMainInst
= (HINSTANCE
) GetWindowLong(ed
->hMainWnd
, GWL_HINSTANCE
);
526 // set up the new window's class
527 memset(&wc
, 0, sizeof(WNDCLASS
));
528 wc
.style
= CS_HREDRAW
| CS_VREDRAW
;
529 wc
.lpfnWndProc
= PropertyListEditorWndProc
;
530 wc
.hInstance
= hMainInst
;
531 wc
.hbrBackground
= (HBRUSH
) GetStockObject(LTGRAY_BRUSH
);
532 wc
.lpszClassName
= szName
;
538 GetWindowRect(ed
->hMainWnd
,&r
);
541 width
= WINDOW_W
+ GetSystemMetrics(SM_CXBORDER
)*2;
542 height
= WINDOW_H
+ GetSystemMetrics(SM_CYBORDER
)*2 + GetSystemMetrics(SM_CYCAPTION
);
544 // chose top left so that not all property editors start in the same place
545 left
= (r
.left
+r
.right
)/4 + num_editors
*MARGIN_X
;
546 top
= r
.top
+ num_editors
*(MARGIN_Y
+GetSystemMetrics(SM_CYCAPTION
));
548 const char* title
= editdesc
->title
;
550 title
= default_title(ed
->editID
);
553 ed
->hWnd
= CreateWindow(szName
, title
, WS_OVERLAPPED
, left
, top
, width
, height
,
554 ed
->hMainWnd
, NULL
, hMainInst
, NULL
);
556 ShowWindow(ed
->hWnd
, SW_SHOWNORMAL
);
557 UpdateWindow(ed
->hWnd
);
559 // Create a nice standard Windows font for the controls.
561 memset(&logFont
, 0, sizeof(LOGFONT
));
562 logFont
.lfCharSet
= DEFAULT_CHARSET
;
563 logFont
.lfHeight
= 12;
564 strcpy(logFont
.lfFaceName
, "MS Sans Serif");
565 ed
->hWndFont
= CreateFontIndirect(&logFont
);
570 // get our new window's HINSTANCE
571 ed
->hInst
= (HINSTANCE
) GetWindowLong(ed
->hWnd
, GWL_HINSTANCE
);
573 // now, let's create the meta property box
574 ed
->hWndMetaBox
= CreateWindow("LISTBOX", "MetaProperties", WS_VISIBLE
| WS_CHILD
| LBS_STANDARD
,
575 left
, top
, METABOX_W
, METABOX_H
, ed
->hWnd
, (HMENU
) ID_METABOX
,
577 top
+= METABOX_H
+ MARGIN_Y
;
580 SendMessage(ed
->hWndMetaBox
, WM_SETFONT
, (WPARAM
)ed
->hWndFont
, 0);
582 // now, let's create the property box
583 ed
->hWndPropBox
= CreateWindow("LISTBOX", "Properties", WS_VISIBLE
| WS_CHILD
| LBS_STANDARD
,
584 left
, top
, PROPBOX_W
, PROPBOX_H
, ed
->hWnd
, (HMENU
) ID_PROPBOX
,
586 top
+= PROPBOX_H
+ MARGIN_Y
;
589 SendMessage(ed
->hWndPropBox
, WM_SETFONT
, (WPARAM
)ed
->hWndFont
, 0);
591 // compute first button position
592 left
= (width
- BUTTONS_W
)/2;
594 // create some buttons
595 for (int i
= 0; i
< NUM_BUTTONS
; i
++, left
+= BUTTON_W
+ MARGIN_X
)
598 = CreateWindow("BUTTON", button_names
[i
], WS_VISIBLE
| WS_CHILD
| BS_PUSHBUTTON
,
599 left
, top
, BUTTON_W
, BUTTON_H
, ed
->hWnd
, (HMENU
) i
, ed
->hInst
, NULL
);
601 SendMessage(ed
->hWndButtons
[i
], WM_SETFONT
, (WPARAM
)ed
->hWndFont
, 0);
605 //-----------------------------------------------------------------------------
606 // Tears down all the GUI stuff, after "Done" is clicked.
607 //-----------------------------------------------------------------------------
608 void PropertyListEditorDestroy(PropertyListEditor
* ed
)
615 DeleteObject(ed
->hWndFont
);
620 SetFocus(ed
->hMainWnd
);
625 Warning(("PropertyListEditorDestroy: Not editing an object!\n"));