convert line ends
[canaan.git] / prj / cam / src / editor / editplst.cpp
blob75aaaa7612f66813898dfc620cc277ad61e97260
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 // $Header: r:/t2repos/thief2/src/editor/editplst.cpp,v 1.14 1998/03/14 21:07:57 mahk Exp $
8 // Property List Editor
10 #include <editplst.h>
11 #include <editprop.h>
12 #include <sdesbase.h>
13 #include <sdesc.h>
15 #include <property.h>
16 #include <propbase.h>
17 #include <propman.h>
18 #include <propraw.h>
20 #include <appagg.h>
21 #include <traitman.h>
22 #include <traitbas.h>
23 #include <objquery.h>
24 #include <iobjsys.h>
25 #include <objedit.h>
26 #include <donorq.h>
27 #include <label.h>
30 // for the windows controls
31 #define WIN32_LEAN_AND_MEAN
32 #include <windows.h>
33 #include <commdlg.h>
34 #include <commctrl.h>
36 #include <comtools.h>
37 #include <wappapi.h>
38 #include <appagg.h>
39 #include <stdlib.H>
41 // must be last header
42 #include <dbmem.h>
44 // control IDs
45 #define ID_VIEWBUTTON 0
46 #define ID_DELETEBUTTON 1
47 #define ID_DONEBUTTON 2
48 #define ID_PROPBOX 3
49 #define ID_METABOX 4
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" };
58 // Dimensions
60 #define BUTTON_W (65 +GetSystemMetrics(SM_CXBORDER)*2)
61 #define BUTTON_H (25 +GetSystemMetrics(SM_CYBORDER)*2)
64 #define PROPBOX_W 200
65 #define PROPBOX_H 200
67 #define METABOX_W 200
68 #define METABOX_H 100
70 #define MARGIN_X 5
71 #define MARGIN_Y 5
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)
78 //----------------
79 // GLOBALS
80 //----------------
82 static int num_editors = 0; // number of editors currently out there.
84 //----------------
85 // Prototypes
86 //----------------
87 void BuildUI(PropertyListEditor* ed, PropertyListEditorDesc* editdesc);
88 void PropertyListEditorDestroy(PropertyListEditor* ed);
90 // these flags tell PropertyListEditorFillBox which properties to display
91 #define kIrrelevant 0
92 #define kRelevant 1
94 static char* view_button_text[] = { "Cancel", "Add" };
97 //------------------------------------------------------------
98 // General ops
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)
108 return;
110 ed->mode = 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)
129 static char buf[80];
130 sprintf(buf,"%s",prop->Describe()->name);
132 if (!prop->IsSimplyRelevant(obj))
133 return buf;
135 AutoAppIPtr_(StructDescTools,pTools);
136 const sPropertyTypeDesc* tdesc = prop->DescribeType();
137 const sStructDesc* sdesc = pTools->Lookup(tdesc->type);
138 if (tdesc->size > 0 && sdesc )
140 IPropertyRaw* raw;
141 if (FAILED(COMQueryInterface(prop,IID_IPropertyRaw,(void**)&raw)))
142 return buf;
144 // grab the data
145 char* val = new char[tdesc->size];
146 raw->Get(obj,val);
148 // add a colon and the value
149 strcat(buf,": ");
150 pTools->UnparseSimple(sdesc,val,buf+strlen(buf),sizeof(buf)-strlen(buf));
151 delete val;
154 return buf;
157 extern "C"
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);
166 sPropertyIter iter;
167 IProperty* prop;
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))
177 continue;
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));
184 SafeRelease(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)
199 char buf[80];
200 AutoAppIPtr_(PropertyManager,propMan);
202 int index = SendMessage(ed->hWndPropBox, LB_GETCURSEL, 0, 0);
203 if (index == LB_ERR)
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);
214 return prop;
218 #pragma off(unreferenced)
219 static void handle_propbox_command(PropertyListEditor* ed, WPARAM wParam, LPARAM lParam)
221 switch (HIWORD(wParam))
223 case LBN_DBLCLK:
225 IProperty* prop = selected_property(ed);
226 if (ed->mode == kIrrelevant)
227 prop->Create(ed->editID);
228 PropertyEditor* ped = PropertyEditorCreate(prop, ed->editID);
229 if (ped)
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);
240 SafeRelease(prop);
242 break;
244 case LBN_SELCHANGE:
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);
253 break;
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))
281 return;
283 if (mode == kRelevant)
285 donors = traitman->Query(ed->editID,kTraitQueryDonors);
286 COMQueryInterface(donors,IID_IDonorQuery,(void**)&dq);
288 else
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))
297 continue;
299 const Label* name = objsys->GetName(obj);
300 Assert_(name);
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));
307 SafeRelease(dq);
308 SafeRelease(donors);
311 static ObjID selected_metaproperty(PropertyListEditor* ed)
313 // char buf[80];
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);
322 Label label;
323 strncpy(label.text,buf,sizeof(label.text));
324 label.text[sizeof(label.text)-1] = '\0';
327 return pObjectSystem->GetObjectNamed(&label);
328 #endif
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);
339 if (index == LB_ERR)
340 return;
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))
356 case LBN_DBLCLK:
359 ObjID mprop = selected_metaproperty(ed);
360 if (mprop == OBJ_NULL) break;
362 if (ed->mode == kRelevant)
364 PropertyListEditorDesc edesc = { "" };
365 PropertyListEditorCreate(mprop, &edesc);
367 else
369 AutoAppIPtr_(TraitManager,traitman);
370 traitman->AddObjMetaProperty(ed->editID,mprop);
371 // snap back to relevant mode
372 change_edit_mode(ed,kRelevant);
375 break;
377 case LBN_SELCHANGE:
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);
386 break;
389 #pragma on(unreferenced)
391 //------------------------------------------------------------
392 // RANDOM UI TOOLS
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)
407 HWND parent;
408 PropertyListEditor *ed;
410 // get the PropertyListEditor* from the parent window
411 parent = GetParent(hWnd);
412 if (parent == NULL)
413 parent = hWnd;
414 ed = (PropertyListEditor*) GetProp(parent, ID_PLISTED);
416 switch(msg)
418 case WM_COMMAND:
419 switch(LOWORD(wParam))
421 case ID_VIEWBUTTON:
422 // switch from add mode to view mode
423 change_edit_mode(ed,!ed->mode);
425 break;
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);
440 else
442 remove_selected_metaproperty(ed);
445 SafeRelease(prop);
448 break;
450 case ID_DONEBUTTON:
451 DestroyWindow(ed->hWnd);
452 return 0;
454 case ID_PROPBOX:
455 handle_propbox_command(ed,wParam,lParam);
456 break;
458 case ID_METABOX:
459 handle_metabox_command(ed,wParam,lParam);
460 break;
463 return 0;
465 case WM_DESTROY:
466 PropertyListEditorDestroy(ed);
467 return 0;
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));
484 ed->editID = editID;
485 ed->mode = kRelevant;
487 num_editors++;
488 BuildUI(ed, editdesc);
489 SetProp(ed->hWnd, ID_PLISTED, (HANDLE)ed);
490 PropertyListEditorFillBox(ed, ed->mode);
491 PropertyListEditorFillMetaBox(ed, ed->mode);
493 return ed;
497 // Create default title
500 static const char* default_title(ObjID obj)
502 static char buf[80];
503 sprintf(buf,"Properties for %s",ObjEditName(obj));
504 return buf;
507 //-----------------------------------------------------------------------------
508 // Create all the GUI elements needed to show the property list.
509 //-----------------------------------------------------------------------------
510 void BuildUI(PropertyListEditor* ed, PropertyListEditorDesc* editdesc)
512 IWinApp* pWA;
513 WNDCLASS wc;
514 HINSTANCE hMainInst;
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();
521 SafeRelease(pWA);
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;
534 // and register it
535 RegisterClass(&wc);
537 RECT r;
538 GetWindowRect(ed->hMainWnd,&r);
540 // make it so big
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;
549 if (*title == '\0')
550 title = default_title(ed->editID);
552 // and create it!
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.
560 LOGFONT logFont;
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);
567 left = MARGIN_X;
568 top = MARGIN_Y;
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,
576 ed->hInst, NULL);
577 top += METABOX_H + MARGIN_Y;
579 if (ed->hWndFont)
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,
585 ed->hInst, NULL);
586 top += PROPBOX_H + MARGIN_Y;
588 if (ed->hWndFont)
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)
597 ed->hWndButtons[i]
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);
600 if (ed->hWndFont)
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)
610 // Tear down our UI.
611 if (ed)
613 if (ed->hWndFont)
615 DeleteObject(ed->hWndFont);
616 ed->hWndFont = 0;
618 ed->hWnd = 0;
619 ed->hInst = 0;
620 SetFocus(ed->hMainWnd);
621 Free(ed);
622 num_editors--;
624 else
625 Warning(("PropertyListEditorDestroy: Not editing an object!\n"));